diff --git a/.eslintrc.js b/.eslintrc.js index 455b2e1..bc00a36 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,23 +1,23 @@ module.exports = { - env: { - browser: true, - es2021: true, - }, - extends: [ - 'eslint:recommended', - 'plugin:vue/essential', - 'plugin:@typescript-eslint/recommended', - 'prettier/@typescript-eslint', - ], - parserOptions: { - ecmaVersion: 'latest', - parser: '@typescript-eslint/parser', - sourceType: 'module', - }, - plugins: ['vue', '@typescript-eslint'], - rules: { - // override/add rules settings here, such as: - 'vue/no-unused-vars': 'error', - 'vue/script-setup-uses-vars': 'off', - }, -} + env: { + browser: true, + es2021: true, + }, + extends: [ + 'eslint:recommended', + 'plugin:vue/essential', + 'plugin:@typescript-eslint/recommended', + 'prettier/@typescript-eslint', + ], + parserOptions: { + ecmaVersion: 'latest', + parser: '@typescript-eslint/parser', + sourceType: 'module', + }, + plugins: ['vue', '@typescript-eslint'], + rules: { + // override/add rules settings here, such as: + 'vue/no-unused-vars': 'error', + 'vue/script-setup-uses-vars': 'off', + }, +}; diff --git a/.prettierrc b/.prettierrc index b4c9912..f75271c 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,11 +1,11 @@ { - "semi": false, - "tabWidth": 2, - "useTabs": false, - "printWidth": 80, - "endOfLine": "auto", - "singleQuote": true, - "trailingComma": "es5", - "bracketSpacing": true, - "arrowParens": "always" + "semi": true, + "tabWidth": 4, + "useTabs": false, + "printWidth": 80, + "endOfLine": "auto", + "singleQuote": true, + "trailingComma": "es5", + "bracketSpacing": true, + "arrowParens": "always" } diff --git a/docs/proc-uml.svg b/docs/proc-uml.svg new file mode 100644 index 0000000..34441a3 --- /dev/null +++ b/docs/proc-uml.svg @@ -0,0 +1,88 @@ +Regexid: numberregex: RegExpConstraintRegexlocation: LocationLocationBEFOREAFTERValueRegexRegexGroupid: numbervalueRegex?: ValueRegex | undefinedconstraintRegex: ConstraintRegex[]enabled: booleanCaptureAreaid: numberwidth: numberheight: numbertop: numberleft: numberregexGroups: RegexGroup[]enabled: booleanDesktopVideoStreamcurrentSelectedSource: ObjectdesktopCaptureSources: Object[]isLoadingScreensAndApplications: booleaninstance: DesktopVideoStreamfetchAllMediaStreams(): Promise<void>getDesktopCaptureSources(): Promise<void>getStreamSource(source: any): Promise<MediaStream>setCurrentSelectedSource(source: Object): voidsetIsLoadingScreensAndApplications(value: boolean): voidgetIsLoadingScreensAndApplications(): booleangetCurrentSelectedSource(): ObjectgetMainScreenSource(): ObjectgetOnlyScreenSources(): Object[]getOnlyApplicationSources(): Object[]getScreenAndApplicationSources(): Object[]getInstance(): DesktopVideoStreamRegexHandlerTesseractHandlerstream?: MediaStream | undefinedworker: Worker[]enabledCaptureAreas: CaptureArea[]Vigadmain(): void11*** \ No newline at end of file diff --git a/electron-builder.json5 b/electron-builder.json5 index 65395f9..1bf967d 100644 --- a/electron-builder.json5 +++ b/electron-builder.json5 @@ -2,36 +2,29 @@ * @see https://www.electron.build/configuration/configuration */ { - "appId": "YourAppID", - "asar": true, - "directories": { - "output": "release/${version}" - }, - "files": [ - "dist-electron", - "dist" - ], - "mac": { - "artifactName": "${productName}_${version}.${ext}", - "target": [ - "dmg" - ] - }, - "win": { - "target": [ - { - "target": "nsis", - "arch": [ - "x64" - ] - } - ], - "artifactName": "${productName}_${version}.${ext}" - }, - "nsis": { - "oneClick": false, - "perMachine": false, - "allowToChangeInstallationDirectory": true, - "deleteAppDataOnUninstall": false - } + appId: 'Vigad4256', + asar: true, + directories: { + output: 'release/${version}', + }, + files: ['dist-electron', 'dist'], + mac: { + artifactName: '${productName}_${version}.${ext}', + target: ['dmg'], + }, + win: { + target: [ + { + target: 'nsis', + arch: ['x64'], + }, + ], + artifactName: '${productName}_${version}.${ext}', + }, + nsis: { + oneClick: false, + perMachine: false, + allowToChangeInstallationDirectory: true, + deleteAppDataOnUninstall: false, + }, } diff --git a/electron/main/index.ts b/electron/main/index.ts index cbe51c7..fcfa06c 100644 --- a/electron/main/index.ts +++ b/electron/main/index.ts @@ -8,25 +8,25 @@ // ├─┬ dist // │ └── index.html > Electron-Renderer // -process.env.DIST_ELECTRON = join(__dirname, '..') -process.env.DIST = join(process.env.DIST_ELECTRON, '../dist') +process.env.DIST_ELECTRON = join(__dirname, '..'); +process.env.DIST = join(process.env.DIST_ELECTRON, '../dist'); process.env.PUBLIC = app.isPackaged - ? process.env.DIST - : join(process.env.DIST_ELECTRON, '../public') + ? process.env.DIST + : join(process.env.DIST_ELECTRON, '../public'); -import { app, BrowserWindow, shell, ipcMain } from 'electron' -import { release } from 'os' -import { join } from 'path' +import { app, BrowserWindow, shell, ipcMain } from 'electron'; +import { release } from 'os'; +import { join } from 'path'; // Disable GPU Acceleration for Windows 7 -if (release().startsWith('6.1')) app.disableHardwareAcceleration() +if (release().startsWith('6.1')) app.disableHardwareAcceleration(); // Set application name for Windows 10+ notifications -if (process.platform === 'win32') app.setAppUserModelId(app.getName()) +if (process.platform === 'win32') app.setAppUserModelId(app.getName()); if (!app.requestSingleInstanceLock()) { - app.quit() - process.exit(0) + app.quit(); + process.exit(0); } // Remove electron security warnings @@ -34,125 +34,128 @@ if (!app.requestSingleInstanceLock()) { // Read more on https://www.electronjs.org/docs/latest/tutorial/security // process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true' -let win: BrowserWindow | null = null +let win: BrowserWindow | null = null; // Here, you can also use other preload -const preload = join(__dirname, '../preload/index.js') -const url = process.env.VITE_DEV_SERVER_URL -const indexHtml = join(process.env.DIST, 'index.html') +const preload = join(__dirname, '../preload/index.js'); +const url = process.env.VITE_DEV_SERVER_URL; +const indexHtml = join(process.env.DIST, 'index.html'); async function createWindow() { - win = new BrowserWindow({ - title: 'Main window', - minWidth: 800, - minHeight: 500, - frame: true, // still buggy cant select items from the custom titlebar - autoHideMenuBar: true, - icon: join(process.env.PUBLIC, 'favicon.ico'), - webPreferences: { - preload, - // Warning: Enable nodeIntegration and disable contextIsolation is not secure in production - // Consider using contextBridge.exposeInMainWorld - // Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation - nodeIntegration: true, - contextIsolation: true, // protect against prototype pollution - }, - }) - - const remoteMain = require('@electron/remote/main') - remoteMain.initialize() - - if (app.isPackaged) { - win.loadFile(indexHtml) - } else { - win.loadURL(url) - // Open devTool if the app is not packaged - win.webContents.openDevTools() - } - - // Test actively push message to the Electron-Renderer - win.webContents.on('did-finish-load', () => { - win?.webContents.send('main-process-message', new Date().toLocaleString()) - win.setTitle(`Vigad v${1.0}`) - }) - - // Make all links open with the browser, not with the application - win.webContents.setWindowOpenHandler(({ url }) => { - if (url.startsWith('https:')) shell.openExternal(url) - return { action: 'deny' } - }) - - remoteMain.enable(win.webContents) - - // Get all screens/windows from the main process to the renderer process - ipcMain.handle('get-screens', getScreen) - ipcMain.handle('minimize-screen', () => { - win.minimize() - }) - ipcMain.handle('full-screen', () => { - win.isMaximized() ? win.restore() : win.maximize() - }) - ipcMain.handle('close-application', () => { - win.close() - }) + win = new BrowserWindow({ + title: 'Main window', + minWidth: 950, + minHeight: 750, + frame: true, // still buggy cant select items from the custom titlebar + autoHideMenuBar: true, + icon: join(process.env.PUBLIC, '../src/assets/logo.png'), + webPreferences: { + preload, + // Warning: Enable nodeIntegration and disable contextIsolation is not secure in production + // Consider using contextBridge.exposeInMainWorld + // Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation + nodeIntegration: true, + contextIsolation: true, // protect against prototype pollution + }, + }); + + const remoteMain = require('@electron/remote/main'); + remoteMain.initialize(); + + if (app.isPackaged) { + win.loadFile(indexHtml); + } else { + win.loadURL(url); + // Open devTool if the app is not packaged + win.webContents.openDevTools(); + } + + // Test actively push message to the Electron-Renderer + win.webContents.on('did-finish-load', () => { + win?.webContents.send( + 'main-process-message', + new Date().toLocaleString() + ); + win.setTitle(`Vigad`); + }); + + // Make all links open with the browser, not with the application + win.webContents.setWindowOpenHandler(({ url }) => { + if (url.startsWith('https:')) shell.openExternal(url); + return { action: 'deny' }; + }); + + remoteMain.enable(win.webContents); + + // Get all screens/windows from the main process to the renderer process + ipcMain.handle('get-screens', getScreen); + ipcMain.handle('minimize-screen', () => { + win.minimize(); + }); + ipcMain.handle('full-screen', () => { + win.isMaximized() ? win.restore() : win.maximize(); + }); + ipcMain.handle('close-application', () => { + win.close(); + }); } -app.whenReady().then(createWindow) +app.whenReady().then(createWindow); app.on('window-all-closed', () => { - win = null - if (process.platform !== 'darwin') app.quit() -}) + win = null; + if (process.platform !== 'darwin') app.quit(); +}); app.on('second-instance', () => { - if (win) { - // Focus on the main window if the user tried to open another - if (win.isMinimized()) win.restore() - win.focus() - } -}) + if (win) { + // Focus on the main window if the user tried to open another + if (win.isMinimized()) win.restore(); + win.focus(); + } +}); app.on('activate', () => { - const allWindows = BrowserWindow.getAllWindows() - if (allWindows.length) { - allWindows[0].focus() - } else { - createWindow() - } -}) + const allWindows = BrowserWindow.getAllWindows(); + if (allWindows.length) { + allWindows[0].focus(); + } else { + createWindow(); + } +}); // new window example arg: new windows url ipcMain.handle('open-win', (event, arg) => { - const childWindow = new BrowserWindow({ - webPreferences: { - preload, - }, - }) - - if (app.isPackaged) { - childWindow.loadFile(indexHtml, { hash: arg }) - } else { - childWindow.loadURL(`${url}/#${arg}`) - // childWindow.webContents.openDevTools({ mode: "undocked", activate: true }) - } -}) + const childWindow = new BrowserWindow({ + webPreferences: { + preload, + }, + }); + + if (app.isPackaged) { + childWindow.loadFile(indexHtml, { hash: arg }); + } else { + childWindow.loadURL(`${url}/#${arg}`); + // childWindow.webContents.openDevTools({ mode: "undocked", activate: true }) + } +}); async function getScreen(event, title) { - // In the main process. - const { desktopCapturer } = require('electron') - - const allSources = await desktopCapturer.getSources({ - types: ['window', 'screen'], - }) - - // const videoOptionsMenu = Menu.buildFromTemplate([ - // allSources.map((source) => { - // return { - // label: source.name, - // click: () => selectSource(source), - // } - // }), - // ]) - - // videoOptionsMenu.popup() - return allSources + // In the main process. + const { desktopCapturer } = require('electron'); + + const allSources = await desktopCapturer.getSources({ + types: ['window', 'screen'], + }); + + // const videoOptionsMenu = Menu.buildFromTemplate([ + // allSources.map((source) => { + // return { + // label: source.name, + // click: () => selectSource(source), + // } + // }), + // ]) + + // videoOptionsMenu.popup() + return allSources; } diff --git a/index.html b/index.html index 4f1bde2..c075c92 100644 --- a/index.html +++ b/index.html @@ -1,17 +1,17 @@ - - - - - - Vite Apps - - -
- - + + + + + + Vite Apps + + +
+ + diff --git a/package-lock.json b/package-lock.json index 1f69a2f..5b267f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,10 +10,12 @@ "dependencies": { "@electron/remote": "^2.0.8", "@mdi/font": "^7.0.96", + "@types/webfontloader": "^1.6.35", "@vueuse/components": "^9.4.0", "@vueuse/core": "^9.4.0", "roboto-fontface": "^0.10.0", "tesseract.js": "^3.0.3", + "tplant": "^3.1.0", "vue-router": "^4.1.6", "vuetify": "^3.0.1" }, @@ -750,6 +752,11 @@ "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==" }, + "node_modules/@types/webfontloader": { + "version": "1.6.35", + "resolved": "https://registry.npmjs.org/@types/webfontloader/-/webfontloader-1.6.35.tgz", + "integrity": "sha512-IJlrsiDWq6KghQ7tPlL5tcwSUyOxLDceT+AFUY7Ylj0Fcv3/h3QkANqQxZ0B5mEpEKxhTw76vDmvrruSMV9n9Q==" + }, "node_modules/@types/yargs": { "version": "17.0.13", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", @@ -2670,7 +2677,6 @@ "version": "21.3.0", "resolved": "https://registry.npmjs.org/electron/-/electron-21.3.0.tgz", "integrity": "sha512-MGRpshN8fBcx4IRuBABIsGDv0tB/MclIFsyFHFFXsBCUc+vIXaE/E6vuWaniGIFSz5WyeuapfTH5IeRb+7yIfw==", - "dev": true, "hasInstallScript": true, "dependencies": { "@electron/get": "^1.14.1", @@ -5086,6 +5092,11 @@ "node": ">=8" } }, + "node_modules/plantuml-encoder": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/plantuml-encoder/-/plantuml-encoder-1.4.0.tgz", + "integrity": "sha512-sxMwpDw/ySY1WB2CE3+IdMuEcWibJ72DDOsXLkSmEaSzwEUaYBT6DWgOfBiHGCux4q433X6+OEFWjlVqp7gL6g==" + }, "node_modules/plist": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.6.tgz", @@ -5957,6 +5968,28 @@ "node": ">=8.0" } }, + "node_modules/tplant": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tplant/-/tplant-3.1.0.tgz", + "integrity": "sha512-2UJ2MXKvsdik0Xv/5ZVj+UmEngLLV/1TMId3L9WWEeLQg71kH9F3xEgtl/i3ttyusgueDTdsLioOpm7b0GMSUA==", + "dependencies": { + "commander": "^6.1.0", + "glob": "^7.1.6", + "plantuml-encoder": "^1.4.0", + "typescript": "^4.0.3" + }, + "bin": { + "tplant": "dist/index.js" + } + }, + "node_modules/tplant/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "engines": { + "node": ">= 6" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -6028,7 +6061,6 @@ "version": "4.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", - "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7170,6 +7202,11 @@ "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==" }, + "@types/webfontloader": { + "version": "1.6.35", + "resolved": "https://registry.npmjs.org/@types/webfontloader/-/webfontloader-1.6.35.tgz", + "integrity": "sha512-IJlrsiDWq6KghQ7tPlL5tcwSUyOxLDceT+AFUY7Ylj0Fcv3/h3QkANqQxZ0B5mEpEKxhTw76vDmvrruSMV9n9Q==" + }, "@types/yargs": { "version": "17.0.13", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", @@ -8626,7 +8663,6 @@ "version": "21.3.0", "resolved": "https://registry.npmjs.org/electron/-/electron-21.3.0.tgz", "integrity": "sha512-MGRpshN8fBcx4IRuBABIsGDv0tB/MclIFsyFHFFXsBCUc+vIXaE/E6vuWaniGIFSz5WyeuapfTH5IeRb+7yIfw==", - "dev": true, "requires": { "@electron/get": "^1.14.1", "@types/node": "^16.11.26", @@ -10322,6 +10358,11 @@ } } }, + "plantuml-encoder": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/plantuml-encoder/-/plantuml-encoder-1.4.0.tgz", + "integrity": "sha512-sxMwpDw/ySY1WB2CE3+IdMuEcWibJ72DDOsXLkSmEaSzwEUaYBT6DWgOfBiHGCux4q433X6+OEFWjlVqp7gL6g==" + }, "plist": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.6.tgz", @@ -10929,6 +10970,24 @@ "is-number": "^7.0.0" } }, + "tplant": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tplant/-/tplant-3.1.0.tgz", + "integrity": "sha512-2UJ2MXKvsdik0Xv/5ZVj+UmEngLLV/1TMId3L9WWEeLQg71kH9F3xEgtl/i3ttyusgueDTdsLioOpm7b0GMSUA==", + "requires": { + "commander": "^6.1.0", + "glob": "^7.1.6", + "plantuml-encoder": "^1.4.0", + "typescript": "^4.0.3" + }, + "dependencies": { + "commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==" + } + } + }, "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -10981,8 +11040,7 @@ "typescript": { "version": "4.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", - "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", - "dev": true + "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==" }, "universalify": { "version": "0.1.2", @@ -11147,16 +11205,6 @@ "he": "^1.2.0" } }, - "vue-template-compiler": { - "version": "2.7.13", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.13.tgz", - "integrity": "sha512-jYM6TClwDS9YqP48gYrtAtaOhRKkbYmbzE+Q51gX5YDr777n7tNI/IZk4QV4l/PjQPNh/FVa/E92sh/RqKMrog==", - "dev": true, - "requires": { - "de-indent": "^1.0.2", - "he": "^1.2.0" - } - }, "vue-tsc": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.0.9.tgz", diff --git a/package.json b/package.json index d64da30..5d652ed 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "private": true, "scripts": { "dev": "vite", - "build": "vue-tsc --noEmit && vite build && electron-builder" + "build": "vue-tsc --noEmit && vite build && electron-builder", + "gen-uml": "tplant --input src/proc/**/*.ts --output docs/proc-uml.svg -A" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -45,10 +46,12 @@ "dependencies": { "@electron/remote": "^2.0.8", "@mdi/font": "^7.0.96", + "@types/webfontloader": "^1.6.35", "@vueuse/components": "^9.4.0", "@vueuse/core": "^9.4.0", "roboto-fontface": "^0.10.0", "tesseract.js": "^3.0.3", + "tplant": "^3.1.0", "vue-router": "^4.1.6", "vuetify": "^3.0.1" } diff --git a/src/App.vue b/src/App.vue index eda6c0b..30184d4 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,334 +1,128 @@ diff --git a/src/assets/electron.svg b/src/assets/electron.svg deleted file mode 100644 index 1c5cccb..0000000 --- a/src/assets/electron.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/assets/logo.png b/src/assets/logo.png new file mode 100644 index 0000000..5677414 Binary files /dev/null and b/src/assets/logo.png differ diff --git a/src/assets/vite.svg b/src/assets/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/src/assets/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/assets/vue.svg b/src/assets/vue.svg deleted file mode 100644 index 770e9d3..0000000 --- a/src/assets/vue.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/components/MainVideoStream.vue b/src/components/MainVideoStream.vue new file mode 100644 index 0000000..82a176c --- /dev/null +++ b/src/components/MainVideoStream.vue @@ -0,0 +1,58 @@ + + + + + + diff --git a/src/components/VideoStream.vue b/src/components/VideoStream.vue deleted file mode 100644 index 68aeeeb..0000000 --- a/src/components/VideoStream.vue +++ /dev/null @@ -1,156 +0,0 @@ - - - - - diff --git a/src/components/ViewComponent.vue b/src/components/ViewComponent.vue new file mode 100644 index 0000000..9ce83fe --- /dev/null +++ b/src/components/ViewComponent.vue @@ -0,0 +1,25 @@ + + + + + + + diff --git a/src/components/capture-area/CaptureAreaActions.vue b/src/components/capture-area/CaptureAreaActions.vue deleted file mode 100644 index 79fe59f..0000000 --- a/src/components/capture-area/CaptureAreaActions.vue +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/src/components/capture-area/CaptureAreaMetaProperties.vue b/src/components/capture-area/CaptureAreaMetaProperties.vue index 186d456..22a1083 100644 --- a/src/components/capture-area/CaptureAreaMetaProperties.vue +++ b/src/components/capture-area/CaptureAreaMetaProperties.vue @@ -1,84 +1,98 @@ - + diff --git a/src/components/capture-area/CaptureAreaSearchValue.vue b/src/components/capture-area/CaptureAreaSearchValue.vue index ed432ce..bdae6d5 100644 --- a/src/components/capture-area/CaptureAreaSearchValue.vue +++ b/src/components/capture-area/CaptureAreaSearchValue.vue @@ -1,148 +1,155 @@ - + diff --git a/src/composable/useDesktopCapture.ts b/src/composable/useDesktopCapture.ts deleted file mode 100644 index 766e6e1..0000000 --- a/src/composable/useDesktopCapture.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Create all Screen related methodes here and export them -// so they can be used in other files -// ie access the current screen etc. - -// ! use the functions defined in the HomePage.vue file and add documentation to them - -// ! properly document each function and add @return to every function - -import { ref } from 'vue' - -export const isLoadingScreensAndWindows = ref(false) -export const allSources = ref([]) - -export const currentScreen = ref(null) -export const currentWindow = ref(null) -export const currentStream = ref(null) - -/** - * Get all the video sources available on the system - */ -export async function getThings() { - // TODO: is not called again if new sources showes up - // Get the available video sources - allSources.value = await (window as any).electronAPI.getMedia() -} diff --git a/src/env.d.ts b/src/env.d.ts index aafef95..dfb2672 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -1,8 +1,8 @@ /// declare module '*.vue' { - import type { DefineComponent } from 'vue' - // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types - const component: DefineComponent<{}, {}, any> - export default component + import type { DefineComponent } from 'vue'; + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types + const component: DefineComponent<{}, {}, any>; + export default component; } diff --git a/src/main.ts b/src/main.ts index b78d634..c169a54 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,12 +1,12 @@ -import { createApp } from 'vue' -import App from './App.vue' -import router from './router/index' -import vuetify from './plugins/vuetify' +import { createApp } from 'vue'; +import App from './App.vue'; +import router from './router/index'; +import vuetify from './plugins/vuetify'; createApp(App) - .use(vuetify) - .use(router) - .mount('#app') - .$nextTick(() => { - postMessage({ payload: 'removeLoading' }, '*') - }) + .use(vuetify) + .use(router) + .mount('#app') + .$nextTick(() => { + postMessage({ payload: 'removeLoading' }, '*'); + }); diff --git a/src/plugins/vuetify.ts b/src/plugins/vuetify.ts index cf1a8a5..70b4d80 100644 --- a/src/plugins/vuetify.ts +++ b/src/plugins/vuetify.ts @@ -1,51 +1,51 @@ // Styles -import '@mdi/font/css/materialdesignicons.css' -import 'vuetify/styles' // Global CSS has to be imported +import '@mdi/font/css/materialdesignicons.css'; +import 'vuetify/styles'; // Global CSS has to be imported // Vuetify -import { createVuetify, ThemeDefinition } from 'vuetify' +import { createVuetify, ThemeDefinition } from 'vuetify'; // if needed imported -import * as components from 'vuetify/components' -import * as directives from 'vuetify/directives' +import * as components from 'vuetify/components'; +import * as directives from 'vuetify/directives'; // Icons https://materialdesignicons.com/ export default createVuetify({ - theme: { - defaultTheme: 'dark', - themes: { - // Custom Dark Theme - dark: { - dark: true, - colors: { - background: '#121827', - surface: '#181F32', - primary: '#FAD761', - secondary: '#31353E', - font: '#DBE6EB', - error: '#F74343', - info: '#', - success: '#77D679', - warning: '#', + theme: { + defaultTheme: 'dark', + themes: { + // Custom Dark Theme + dark: { + dark: true, + colors: { + background: '#121827', + surface: '#181F32', + primary: '#FAD761', + secondary: '#31353E', + font: '#DBE6EB', + error: '#F74343', + info: '#58a7fe', + success: '#77D679', + warning: '#F74343', + }, + }, + // Custom Light Theme + light: { + dark: false, + colors: { + background: '#ffffff', + surface: '#181F32', + primary: '#DBE6EB', + secondary: '#31353E', + error: '#F74343', + info: '#FAD761', + success: '#77D679', + warning: '#F74343', + }, + }, }, - }, - // Custom Light Theme - light: { - dark: false, - colors: { - background: '#ffffff', - surface: '#181F32', - primary: '#DBE6EB', - secondary: '#31353E', - error: '#F74343', - info: '#FAD761', - success: '#77D679', - warning: '#', - }, - }, }, - }, - components, - directives, -}) + components, + directives, +}); diff --git a/src/plugins/webfontloader.ts b/src/plugins/webfontloader.ts index 6d1fb89..9c147aa 100644 --- a/src/plugins/webfontloader.ts +++ b/src/plugins/webfontloader.ts @@ -5,13 +5,13 @@ */ export async function loadFonts() { - const webFontLoader = await import( - /* webpackChunkName: "webfontloader" */ 'webfontloader' - ) + const webFontLoader = await import( + /* webpackChunkName: "webfontloader" */ 'webfontloader' + ); - webFontLoader.load({ - google: { - families: ['Roboto:100,300,400,500,700,900&display=swap'], - }, - }) + webFontLoader.load({ + google: { + families: ['Roboto:100,300,400,500,700,900&display=swap'], + }, + }); } diff --git a/src/proc/CaptureArea.ts b/src/proc/CaptureArea.ts new file mode 100644 index 0000000..ac2e648 --- /dev/null +++ b/src/proc/CaptureArea.ts @@ -0,0 +1,18 @@ +import { RegexGroup } from "./regex/RegexGroup"; + +export class CaptureArea { + private id: number = 0; + private width: number = 0; + private height: number = 0; + private top: number = 0; + private left: number = 0; + private regexGroups: RegexGroup[] = []; + private enabled: boolean = true; + + public constructor(width:number, height:number, top:number, left:number) { + this.width = width; + this.height = height; + this.top = top; + this.left = left; + } +} \ No newline at end of file diff --git a/src/proc/StreamHandler.ts b/src/proc/StreamHandler.ts new file mode 100644 index 0000000..7c83902 --- /dev/null +++ b/src/proc/StreamHandler.ts @@ -0,0 +1,222 @@ +// Stream handler +export class StreamHandler { + private static instance: StreamHandler; + + private currentSelectedSource: Object; + private desktopCaptureSources: Object[]; + private allMediaStreams: MediaStream[]; + private isLoadingScreensAndApplications: boolean; + + /** + * Create a private constructor to prevent multiple instances + */ + private constructor() { + this.currentSelectedSource = {}; + this.desktopCaptureSources = []; + this.allMediaStreams = []; + this.isLoadingScreensAndApplications = false; + } + + /** + * This function gets the singelton instance of the StreamHandler + * + * @returns the singelton instance of the StreamHandler + */ + public static getInstance(): StreamHandler { + if (!this.instance) { + this.instance = new this(); + } + + return this.instance; + } + + /** + * This function fetches all media streams via the electron desktopCapture API + * + * @returns void + */ + private async fetchAllMediaStreams(): Promise { + this.isLoadingScreensAndApplications = true; + // Get the available video sources + this.desktopCaptureSources = await ( + window as any + ).electronAPI.getMedia(); + this.isLoadingScreensAndApplications = false; + } + + /** + * This function is for setting the loading state + * + * @param value - set isLoadingScreensAndApplications to value new boolean value + * @returns void + */ + public setIsLoadingScreensAndApplications(value: boolean): void { + this.isLoadingScreensAndApplications = value; + } + + /** + * This function returns a boolean which indicates if the StreamHandler is currently loading screens and applications + * + * @returns boolean value if the screens and applications are loading + */ + public getIsLoadingScreensAndApplications(): boolean { + return this.isLoadingScreensAndApplications; + } + + /** + * This function sets the current selected source as the new main video source + * + * @returns the current selected source Object + */ + public getCurrentSelectedSource(): Object { + return this.currentSelectedSource; + } + + /** + * This function returns the media stream from the given source object + * + * @param source - Source object + * @returns a MediaStream from the given source as a Promise + */ + public async getMediaStreamFromSource(source: any): Promise { + // MediaStream Constraints + const constraints: any = { + video: { + mandatory: { + chromeMediaSource: 'desktop', + chromeMediaSourceId: source.id, + }, + }, + }; + + return await navigator.mediaDevices.getUserMedia(constraints); + } + + /** + * This function sets the main screen of the user as the fault video source + * + * @returns a the main screen of the user as a source via a Promise + */ + public async getMainScreenSource(): Promise { + await this.fetchAllMediaStreams(); + // TODO: fix this + return this.desktopCaptureSources[0]; + } + + /** + * This function sets the main monitor screen of the user as the default video source + * + * @returns only a Promise + */ + public async setDefaultVideoStream(): Promise { + const mainScreenSource: any = await this.getMainScreenSource(); + + const mediaStream = await this.getMediaStreamFromSource( + mainScreenSource + ); + + // Set the main video + await this.setCurrentSelectedSource(mediaStream); + } + + /** + * This function sets the current selected source as the new main video source + * + * @param source - MediaStream object + * @returns a MediaStreams as a Promise + */ + public async setCurrentSelectedSource(source: MediaStream) { + if (source === this.currentSelectedSource) return; + + this.currentSelectedSource = source; + + const videoElement: HTMLVideoElement | null = + document.querySelector('#mainVideo'); + + videoElement!.srcObject = source; + } + + /** + * This function returns all available Screen and Application Objects + * + * @returns an array of all available MediaStreams as a Promise + */ + public async getAllMediaStreams(): Promise { + this.allMediaStreams = []; + await this.fetchAllMediaStreams(); + + // Loop through all sources and set the MediaStream to video nodes + Array.from(this.desktopCaptureSources).forEach(async (element: any) => { + this.populateMediaStreamsArray(element); + }); + + return this.allMediaStreams; + } + + /** + * This function will populate the allMediaStreams array with all available MediaStreams + * + * @param source - source object + * @returns only a Promise + */ + private async populateMediaStreamsArray(source: any): Promise { + const constraints: any = { + video: { + mandatory: { + chromeMediaSource: 'desktop', + chromeMediaSourceId: source.id, + }, + }, + }; + + this.allMediaStreams.push( + await navigator.mediaDevices.getUserMedia(constraints) + ); + } + + /** + * This function will return a Mediastream via a specific index which is given as a parameter + * + * @param index - values to search from the allMediaStreams array + * @returns a MediaStream from the given source as a Promise + */ + public async getSpecificMediaStreams(index: number): Promise { + return this.allMediaStreams[index]; + } + + /** + * This function returns all available Screen Objects + * + * @returns an array of all available Screen Objects as a Promise + */ + public async getOnlyScreenSources(): Promise { + await this.fetchAllMediaStreams(); + return this.desktopCaptureSources.filter( + (source: any) => + source.id.substring(0, source.id.indexOf(':')) === 'screen' + ); + } + + /** + * This function returns all available Application Objects + * + * @returns an array of all available Application Objects as a Promise + */ + public async getOnlyApplicationSources(): Promise { + await this.fetchAllMediaStreams(); + return this.desktopCaptureSources.filter( + (source: any) => + source.id.substring(0, source.id.indexOf(':')) === 'window' + ); + } + + /** + * This function returns all available Application and Screen Objects + * + * @returns an array of all available Application and Screen Objects as a Promise + */ + async getScreenAndApplicationSources(): Promise { + await this.fetchAllMediaStreams(); + return this.desktopCaptureSources; + } +} diff --git a/src/proc/TesseractHandler.ts b/src/proc/TesseractHandler.ts new file mode 100644 index 0000000..597b5b7 --- /dev/null +++ b/src/proc/TesseractHandler.ts @@ -0,0 +1,8 @@ +import { createWorker } from 'tesseract.js'; +import { CaptureArea } from './CaptureArea'; + +export class TesseractHandler { + private stream?: MediaStream; + private worker: Worker[] = []; + private enabledCaptureAreas: CaptureArea[] = []; +} \ No newline at end of file diff --git a/src/proc/Vigad.ts b/src/proc/Vigad.ts index bca3df6..70e5d7b 100644 --- a/src/proc/Vigad.ts +++ b/src/proc/Vigad.ts @@ -2,4 +2,4 @@ class Vigad { public main() { // ... } -} \ No newline at end of file +} diff --git a/src/proc/regex/ConstraintRegex.ts b/src/proc/regex/ConstraintRegex.ts new file mode 100644 index 0000000..4bcc550 --- /dev/null +++ b/src/proc/regex/ConstraintRegex.ts @@ -0,0 +1,11 @@ +import { Regex } from "./Regex"; + +export class ConstraintRegex extends Regex { + private location: Location = Location.BEFORE; + +} + +export enum Location { + BEFORE = "Before", + AFTER = "After" +} \ No newline at end of file diff --git a/src/proc/regex/Regex.ts b/src/proc/regex/Regex.ts new file mode 100644 index 0000000..3f42ce3 --- /dev/null +++ b/src/proc/regex/Regex.ts @@ -0,0 +1,4 @@ +export abstract class Regex { + private id: number = 0; + private regex: RegExp = new RegExp(""); +} \ No newline at end of file diff --git a/src/proc/regex/RegexGroup.ts b/src/proc/regex/RegexGroup.ts new file mode 100644 index 0000000..5503fe0 --- /dev/null +++ b/src/proc/regex/RegexGroup.ts @@ -0,0 +1,9 @@ +import { ConstraintRegex } from "./ConstraintRegex"; +import { ValueRegex } from "./ValueRegex"; + +export class RegexGroup { + private id: number = 0; + private valueRegex?: ValueRegex; + private constraintRegex: ConstraintRegex[] = []; + private enabled: boolean = true; +} \ No newline at end of file diff --git a/src/proc/regex/RegexHandler.ts b/src/proc/regex/RegexHandler.ts new file mode 100644 index 0000000..b37c357 --- /dev/null +++ b/src/proc/regex/RegexHandler.ts @@ -0,0 +1,3 @@ +export class RegexHandler { + +} \ No newline at end of file diff --git a/src/proc/regex/ValueRegex.ts b/src/proc/regex/ValueRegex.ts new file mode 100644 index 0000000..d5d7fd9 --- /dev/null +++ b/src/proc/regex/ValueRegex.ts @@ -0,0 +1,5 @@ +import { Regex } from "./Regex"; + +export class ValueRegex extends Regex { + +} \ No newline at end of file diff --git a/src/router/index.ts b/src/router/index.ts index 823547e..a4d7f6f 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,14 +1,14 @@ -import { createRouter, createWebHistory } from 'vue-router' -import { routes } from './routes' +import { createRouter, createWebHistory } from 'vue-router'; +import { routes } from './routes'; const router = createRouter({ - history: createWebHistory(import.meta.env.BASE_URL), - routes, -}) + history: createWebHistory(import.meta.env.BASE_URL), + routes, +}); router.beforeEach((to, from, next) => { - document.title = `${to.meta.title}` - next() -}) + document.title = `${to.meta.title}`; + next(); +}); -export default router +export default router; diff --git a/src/router/routes.ts b/src/router/routes.ts index 6060088..1f56946 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -1,42 +1,42 @@ export const routes = [ - { - name: '404', - path: '/:pathMatch(.*)*', - component: () => import('../views/PageNotFound.vue'), - meta: { - title: 'Vigad - 404 - Page Not Found', + { + name: '404', + path: '/:pathMatch(.*)*', + component: () => import('../views/PageNotFound.vue'), + meta: { + title: 'Vigad - 404 - Page Not Found', + }, }, - }, - { - name: 'error', - path: '/error', - component: () => import('../views/ErrorPage.vue'), - meta: { - title: 'Vigad - Error', + { + name: 'error', + path: '/error', + component: () => import('../views/ErrorPage.vue'), + meta: { + title: 'Vigad - Error', + }, }, - }, - { - name: 'home', - path: '/', - component: () => import('../views/SourcesView.vue'), - meta: { - title: 'Vigad - Sources', + { + name: 'home', + path: '/', + component: () => import('../views/SourcesView.vue'), + meta: { + title: 'Vigad - Sources', + }, }, - }, - { - name: 'run', - path: '/run', - component: () => import('../views/RunPage.vue'), - meta: { - title: 'Vigad - Run', + { + name: 'run', + path: '/run', + component: () => import('../views/RunPage.vue'), + meta: { + title: 'Vigad - Run', + }, }, - }, - { - name: 'regex', - path: '/regex', - component: () => import('../views/RegexView.vue'), - meta: { - title: 'Vigad - Regex', + { + name: 'regex', + path: '/regex', + component: () => import('../views/RegexView.vue'), + meta: { + title: 'Vigad - Regex', + }, }, - }, -] +]; diff --git a/src/styles/variables.scss b/src/styles/variables.scss deleted file mode 100644 index 2937797..0000000 --- a/src/styles/variables.scss +++ /dev/null @@ -1,22 +0,0 @@ -// Call in in css like var(--palette-primary-600); -$palettes: ( - options: ( - transition-duration: 0.25s, - border-radius: 8px, - ), - status: ( - success: #65e699, - danger: #f74343, - active: #58a7fe, - hightlight: #dbe6eb, - ), - text: ( - size: 14px, - color: #dbe6eb, - ), - background: ( - primary: #0f131f, - secondary: #181f32, - tertiary: #313e63, - ), -); diff --git a/src/views/ErrorPage.vue b/src/views/ErrorPage.vue index ae6094b..15a5dfb 100644 --- a/src/views/ErrorPage.vue +++ b/src/views/ErrorPage.vue @@ -1,7 +1,4 @@ - + diff --git a/src/views/HomePage.vue b/src/views/HomePage.vue deleted file mode 100644 index 43e6c32..0000000 --- a/src/views/HomePage.vue +++ /dev/null @@ -1,10 +0,0 @@ - - - - - diff --git a/src/views/PageNotFound.vue b/src/views/PageNotFound.vue index 6788ec0..b1e402a 100644 --- a/src/views/PageNotFound.vue +++ b/src/views/PageNotFound.vue @@ -1,13 +1,14 @@ diff --git a/src/views/RegexView.vue b/src/views/RegexView.vue index c831c34..889a6c1 100644 --- a/src/views/RegexView.vue +++ b/src/views/RegexView.vue @@ -1,31 +1,31 @@ - + diff --git a/src/views/RunPage.vue b/src/views/RunPage.vue index 47c57d6..d7f7a82 100644 --- a/src/views/RunPage.vue +++ b/src/views/RunPage.vue @@ -1,16 +1,24 @@ - + diff --git a/src/views/SourcesView.vue b/src/views/SourcesView.vue index 1c9ce52..64a5550 100644 --- a/src/views/SourcesView.vue +++ b/src/views/SourcesView.vue @@ -1,250 +1,113 @@ -/** - * Load the proper media stream source for the video element - */ -async function loadStreamSources() { - // Is there a better way then this? - const videoElements: HTMLVideoElement | null = - document.querySelectorAll('.preview') - - Array.from(videoElements).forEach(function (video, index) { - setSourceForVideoNode(desktopCaptureSources.value[index], video) - }) + + diff --git a/tsconfig.json b/tsconfig.json index 31fc22b..f4ea4ac 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,21 +1,21 @@ { - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "node", - "importHelpers": true, - "jsx": "preserve", - "esModuleInterop": true, - "resolveJsonModule": true, - "sourceMap": true, - "baseUrl": "./", - "strict": true, - "allowSyntheticDefaultImports": true, - "skipLibCheck": true, - "paths": { - "@/*": ["./src/*"] - } - }, - "include": ["src"], - "references": [{ "path": "./tsconfig.node.json" }] + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "node", + "importHelpers": true, + "jsx": "preserve", + "esModuleInterop": true, + "resolveJsonModule": true, + "sourceMap": true, + "baseUrl": "./", + "strict": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/tsconfig.node.json b/tsconfig.node.json index 82bd5d7..8c1e7b0 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -1,12 +1,12 @@ { - "compilerOptions": { - "target": "ESNext", - "composite": true, - "module": "ESNext", - "moduleResolution": "Node", - "jsx": "preserve", - "resolveJsonModule": true, - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts", "package.json", "electron"] + "compilerOptions": { + "target": "ESNext", + "composite": true, + "module": "ESNext", + "moduleResolution": "Node", + "jsx": "preserve", + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts", "package.json", "electron"] } diff --git a/vite.config.ts b/vite.config.ts index 5f8bfa1..b264153 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,57 +1,57 @@ -import { fileURLToPath, URL } from 'url' -import { rmSync } from 'fs' -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import electron from 'vite-electron-plugin' -import { customStart } from 'vite-electron-plugin/plugin' -import pkg from './package.json' +import { fileURLToPath, URL } from 'url'; +import { rmSync } from 'fs'; +import { defineConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; +import electron from 'vite-electron-plugin'; +import { customStart } from 'vite-electron-plugin/plugin'; +import pkg from './package.json'; -rmSync('dist-electron', { recursive: true, force: true }) +rmSync('dist-electron', { recursive: true, force: true }); // https://vitejs.dev/config/ export default defineConfig({ - plugins: [ - vue(), - electron({ - include: ['electron'], - transformOptions: { - sourcemap: !!process.env.VSCODE_DEBUG, - }, - // Will start Electron via VSCode Debug - plugins: process.env.VSCODE_DEBUG - ? [ - customStart( - debounce(() => - console.log( - /* For `.vscode/.debug.script.mjs` */ '[startup] Electron App' - ) - ) - ), - ] - : undefined, - }), - ], - resolve: { - alias: { - '@': fileURLToPath(new URL('./src', import.meta.url)), + plugins: [ + vue(), + electron({ + include: ['electron'], + transformOptions: { + sourcemap: !!process.env.VSCODE_DEBUG, + }, + // Will start Electron via VSCode Debug + plugins: process.env.VSCODE_DEBUG + ? [ + customStart( + debounce(() => + console.log( + /* For `.vscode/.debug.script.mjs` */ '[startup] Electron App' + ) + ) + ), + ] + : undefined, + }), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)), + }, }, - }, - server: process.env.VSCODE_DEBUG - ? (() => { - const url = new URL(pkg.debug.env.VITE_DEV_SERVER_URL) - return { - host: url.hostname, - port: +url.port, - } - })() - : undefined, - clearScreen: false, -}) + server: process.env.VSCODE_DEBUG + ? (() => { + const url = new URL(pkg.debug.env.VITE_DEV_SERVER_URL); + return { + host: url.hostname, + port: +url.port, + }; + })() + : undefined, + clearScreen: false, +}); function debounce void>(fn: Fn, delay = 299) { - let t: NodeJS.Timeout - return ((...args) => { - clearTimeout(t) - t = setTimeout(() => fn(...args), delay) - }) as Fn + let t: NodeJS.Timeout; + return ((...args) => { + clearTimeout(t); + t = setTimeout(() => fn(...args), delay); + }) as Fn; }