From d5210adc0d7b7160b690d6517e3f54f3321aba8c Mon Sep 17 00:00:00 2001 From: Dmitry Reshetnikov Date: Thu, 10 Apr 2025 19:33:25 +0300 Subject: [PATCH 1/4] feat: add russian localization to browser version --- browser/src/i18n/languages.ts | 1 + browser/src/i18n/locales/ru.ts | 65 ++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 browser/src/i18n/locales/ru.ts diff --git a/browser/src/i18n/languages.ts b/browser/src/i18n/languages.ts index 7ab3289..5f4ba5b 100644 --- a/browser/src/i18n/languages.ts +++ b/browser/src/i18n/languages.ts @@ -1,5 +1,6 @@ const languages = [ { key: 'en', name: 'English' }, + { key: 'ru', name: 'Русский' }, { key: 'zh', name: '中文' } ]; diff --git a/browser/src/i18n/locales/ru.ts b/browser/src/i18n/locales/ru.ts new file mode 100644 index 0000000..8cb76e7 --- /dev/null +++ b/browser/src/i18n/locales/ru.ts @@ -0,0 +1,65 @@ +const ru = { + translation: { + serial: { + notSupported: + 'Подключение к последовательному порту не поддерживается. Чтобы пользоваться мышью и клавиатурой, используйте браузер Chrome для настольных компьютеров.', + failed: 'Не удалось установить подключение к последовательному порту. Пожалуйста, попробуйте еще раз.' + }, + camera: { + tip: 'Ожидание доступа...', + denied: 'Доступ отказан', + authorize: + 'Для удаленного рабочего стола требуется доступ к камере. Пожалуйста, разрешите доступ к камеру в настройках браузера.', + failed: 'Не удалось подключить камеру. Пожалуйста, попробуйте еще раз.' + }, + modal: { + title: 'Выберите устройство USB', + selectVideo: 'Выбрать источник видео', + selectSerial: 'Выбрать последовательный порт' + }, + menu: { + serial: 'Последовательный порт', + keyboard: 'Клавиатура', + mouse: 'Мышь' + }, + video: { + resolution: 'Разрешение', + customResolution: 'Пользовательское', + device: 'Видеоустройство', + custom: { + title: 'Пользовательское разрешение', + width: 'Ширина', + height: 'Высота', + confirm: 'Ок', + cancel: 'Отмена' + } + }, + keyboard: { + paste: 'Вставить текст', + virtualKeyboard: 'Виртуальная клавиатура' + }, + mouse: { + cursor: { + title: 'Курсор', + pointer: 'Указатель', + grab: 'Захват', + cell: 'Прицел', + hide: 'Скрытый' + }, + mode: 'Режим мыши', + absolute: 'Абсолютное позиционирование', + relative: 'Относительное позиционирование', + direction: 'Направление прокрутки', + scrollUp: 'Обычное', + scrollDown: 'Инвертированное', + requestPointer: 'Используется относительное позиционирование мыши. Чтобы захватить курсор, щелкните по видео на экране' + }, + settings: { + language: 'Язык приложения', + document: 'Документация', + download: 'Загрузить' + } + } +}; + +export default ru; From b5c12ffbf55dcd69af578fb40bcce31f286983b9 Mon Sep 17 00:00:00 2001 From: Dmitry Reshetnikov Date: Fri, 11 Apr 2025 01:14:52 +0300 Subject: [PATCH 2/4] review fix --- browser/src/i18n/locales/ru.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/src/i18n/locales/ru.ts b/browser/src/i18n/locales/ru.ts index 8cb76e7..fe21c13 100644 --- a/browser/src/i18n/locales/ru.ts +++ b/browser/src/i18n/locales/ru.ts @@ -9,7 +9,7 @@ const ru = { tip: 'Ожидание доступа...', denied: 'Доступ отказан', authorize: - 'Для удаленного рабочего стола требуется доступ к камере. Пожалуйста, разрешите доступ к камеру в настройках браузера.', + 'Для удаленного рабочего стола требуется доступ к камере. Пожалуйста, разрешите доступ к камере в настройках браузера.', failed: 'Не удалось подключить камеру. Пожалуйста, попробуйте еще раз.' }, modal: { From 27ec31c76ea90f55c5231bb17fb8d84a7d70b3d9 Mon Sep 17 00:00:00 2001 From: "Geovanny F. Fajardo" Date: Thu, 17 Apr 2025 14:39:00 -0400 Subject: [PATCH 3/4] Fix issue with audio support. --- desktop/README.md | 16 +++++++++++ desktop/electron-builder.yml | 28 +++++++++++++++---- desktop/src/main/index.ts | 12 +++++++- .../src/components/menu/video/device.tsx | 20 +++++++++++-- desktop/src/renderer/src/libs/camera/index.ts | 5 ++-- 5 files changed, 69 insertions(+), 12 deletions(-) diff --git a/desktop/README.md b/desktop/README.md index 263cb25..71c63ed 100644 --- a/desktop/README.md +++ b/desktop/README.md @@ -2,8 +2,17 @@ This is the NanoKVM-USB desktop version project. + ## Development +Linux build tool chain: + +```shell +sudo apt update +sudo apt install -y build-essential python3 libudev-dev +echo "python=/usr/bin/python3.10" >> ~/.npmrc # This should match you pyton version. +``` + ```shell cd desktop pnpm install @@ -22,3 +31,10 @@ pnpm build:mac # For Linux pnpm build:linux ``` + +# For Linux run and install +```shell +dpkg -i dist/nanokvm-usb_1.0.0_amd64.deb +sudo chown root:root /opt/NanoKVM-USB/chrome-sandbox +sudo chmod 4755 /opt/NanoKVM-USB/chrome-sandbox +``` diff --git a/desktop/electron-builder.yml b/desktop/electron-builder.yml index 4695ba3..0d54a31 100644 --- a/desktop/electron-builder.yml +++ b/desktop/electron-builder.yml @@ -1,7 +1,9 @@ appId: com.sipeed.usbkvm productName: NanoKVM-USB + directories: buildResources: build + files: - '!**/.vscode/*' - '!src/*' @@ -9,30 +11,39 @@ files: - '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}' - '!{.env,.env.*,.npmrc,pnpm-lock.yaml}' - '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}' + asarUnpack: - resources/** + win: executableName: NanoKVM-USB + nsis: - onClick: false + oneClick: false # show installer wizard + perMachine: true # install for all users allowToChangeInstallationDirectory: true + allowElevation: true # request elevation when needed artifactName: ${productName}-${version}-setup.${ext} shortcutName: ${productName} uninstallDisplayName: ${productName} - createDesktopShortcut: always + createDesktopShortcut: true + createStartMenuShortcut: true + mac: entitlementsInherit: build/entitlements.mac.plist extendInfo: - - NSCameraUsageDescription: Application requests access to the device's camera. - - NSMicrophoneUsageDescription: Application requests access to the device's microphone. - - NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder. - - NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder. + NSCameraUsageDescription: Application requests access to the device's camera. + NSMicrophoneUsageDescription: Application requests access to the device's microphone. + NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder. + NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder. hardenedRuntime: true gatekeeperAssess: false notarize: false + dmg: artifactName: ${productName}-${version}.${ext} sign: true + linux: target: - AppImage @@ -40,13 +51,18 @@ linux: - deb maintainer: sipeed.com category: Utility + appImage: artifactName: ${productName}-${version}.${ext} + npmRebuild: false + afterSign: "./notarize.js" + publish: provider: github owner: sipeed repo: NanoKVM-USB + electronDownload: mirror: https://npmmirror.com/mirrors/electron/ diff --git a/desktop/src/main/index.ts b/desktop/src/main/index.ts index f0bc571..6e37dfc 100644 --- a/desktop/src/main/index.ts +++ b/desktop/src/main/index.ts @@ -1,6 +1,6 @@ import { join } from 'path' import { electronApp, is, optimizer } from '@electron-toolkit/utils' -import { app, BrowserWindow, shell } from 'electron' +import { app, BrowserWindow, shell, session } from 'electron' import log from 'electron-log/main' import icon from '../../resources/icon.png?asset' @@ -26,6 +26,7 @@ function createWindow(): void { mainWindow.on('ready-to-show', () => { mainWindow.show() mainWindow.maximize() + //mainWindow.webContents.openDevTools() }) mainWindow.webContents.setWindowOpenHandler((details) => { @@ -43,6 +44,15 @@ function createWindow(): void { app.whenReady().then(() => { electronApp.setAppUserModelId('com.sipeed.usbkvm') + session.defaultSession.setPermissionRequestHandler((webContents, permission, callback, details) => { + console.log('Permission requested:', permission) + if (permission === 'media') { + callback(true) + } else { + callback(false) + } + }) + app.on('browser-window-created', (_, window) => { optimizer.watchWindowShortcuts(window) }) diff --git a/desktop/src/renderer/src/components/menu/video/device.tsx b/desktop/src/renderer/src/components/menu/video/device.tsx index 20bef48..f4448e8 100644 --- a/desktop/src/renderer/src/components/menu/video/device.tsx +++ b/desktop/src/renderer/src/components/menu/video/device.tsx @@ -18,10 +18,19 @@ export const Device = (): ReactElement => { const [isLoading, setIsLoading] = useState(false) useEffect(() => { - navigator.mediaDevices.enumerateDevices().then((deviceInfo) => { + ;(async () => { + try { + // Prompt for camera access to unlock device labels + await navigator.mediaDevices.getUserMedia({ video: true }) + } catch (err) { + console.error('Camera permission denied:', err) + return + } + + const deviceInfo = await navigator.mediaDevices.enumerateDevices() const videoDevices = deviceInfo.filter((device) => device.kind === 'videoinput') setDevices(videoDevices) - }) + })() }, []) async function selectDevice(deviceId: string): Promise { @@ -36,6 +45,13 @@ export const Device = (): ReactElement => { if (!video) return video.srcObject = camera.getStream() + // Start playback explicitly + try { + await video.play() + } catch (err) { + console.error('video.play() failed:', err) + } + setVideoDeviceId(deviceId) storage.setVideoDevice(deviceId) } finally { diff --git a/desktop/src/renderer/src/libs/camera/index.ts b/desktop/src/renderer/src/libs/camera/index.ts index 186785c..1f9a25d 100644 --- a/desktop/src/renderer/src/libs/camera/index.ts +++ b/desktop/src/renderer/src/libs/camera/index.ts @@ -17,8 +17,7 @@ class Camera { deviceId: { exact: id || this.id }, width: { ideal: width || this.width }, height: { ideal: height || this.height } - }, - audio: true + } } this.stream = await navigator.mediaDevices.getUserMedia(constraints) @@ -49,4 +48,4 @@ class Camera { } } -export const camera = new Camera() +export const camera = new Camera() \ No newline at end of file From 90f7034c26d2e2ab7f2d2860716b3f501ad27186 Mon Sep 17 00:00:00 2001 From: wj-xiao Date: Fri, 18 Apr 2025 18:22:48 +0800 Subject: [PATCH 4/4] fixed audio output issue --- browser/src/App.tsx | 2 +- browser/src/components/device-modal/index.tsx | 127 ++---------------- .../components/device-modal/serial-port.tsx | 59 ++++++++ browser/src/components/device-modal/video.tsx | 109 +++++++++++++++ browser/src/components/menu/video/device.tsx | 58 +++++--- .../src/components/menu/video/resolution.tsx | 8 +- browser/src/libs/camera/index.ts | 37 +++-- browser/src/types.ts | 7 + desktop/src/main/index.ts | 3 +- desktop/src/renderer/src/App.tsx | 2 +- .../src/components/device-modal/video.tsx | 86 ++++++++---- .../src/components/menu/video/device.tsx | 69 ++++++---- .../src/components/menu/video/resolution.tsx | 8 +- desktop/src/renderer/src/libs/camera/index.ts | 40 +++--- desktop/src/renderer/src/types.ts | 7 + 15 files changed, 386 insertions(+), 236 deletions(-) create mode 100644 browser/src/components/device-modal/serial-port.tsx create mode 100644 browser/src/components/device-modal/video.tsx diff --git a/browser/src/App.tsx b/browser/src/App.tsx index 11cdfd1..2c11e7a 100644 --- a/browser/src/App.tsx +++ b/browser/src/App.tsx @@ -106,7 +106,7 @@ const App = () => {