diff --git a/.github/workflows/dev-release.yml b/.github/workflows/dev-release.yml index 96bb469..4f68997 100644 --- a/.github/workflows/dev-release.yml +++ b/.github/workflows/dev-release.yml @@ -42,11 +42,19 @@ jobs: python3 -m ensurepip --upgrade python3 -m pip install --upgrade pip setuptools + - name: Setup LXD for Snapcraft + if: matrix.os == 'ubuntu-latest' + uses: canonical/setup-lxd@v0.1.2 + with: + channel: latest/stable + - name: Install Linux build deps if: matrix.os == 'ubuntu-latest' run: | sudo apt-get update - sudo apt-get install -y libx11-dev libxext-dev libxtst-dev libxkbcommon-x11-dev libxkbfile-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxt-dev + sudo apt-get install -y libx11-dev libxext-dev libxtst-dev libxkbcommon-x11-dev libxkbfile-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxt-dev libpipewire-0.3-dev libpulse-dev + sudo snap install core22 + sudo snap install snapcraft --classic --channel=7.x/stable - name: Install dependencies run: npm install @@ -54,6 +62,11 @@ jobs: - name: Build Electron App shell: bash run: | + if [ "${{ matrix.name }}" = "nsis" ]; then + export WIN_CSC_LINK="${{ secrets.WIN_CERTS_BASE64 }}" + export WIN_CSC_KEY_PASSWORD="${{ secrets.WIN_CERTS_PASSWORD }}" + fi + if [ "${{ matrix.name }}" = "linux" ]; then npm run build:linux elif [ "${{ matrix.name }}" = "nsis" ]; then @@ -89,52 +102,52 @@ jobs: } shell: powershell - # ✅ Windows için eSigner ile imzala - NSIS Installer - - name: Sign NSIS Installer - if: matrix.os == 'windows-latest' && matrix.name == 'nsis' - uses: sslcom/esigner-codesign@develop - with: - command: sign - username: ${{ secrets.ESIGNER_USERNAME }} - password: ${{ secrets.ESIGNER_PASSWORD }} - credential_id: ${{ secrets.ESIGNER_CREDENTIAL_ID }} - totp_secret: ${{ secrets.ESIGNER_TOTP }} - file_path: dist/Topluyo-Setup-${{ steps.package-version.outputs.version }}.exe - malware_block: false - override: true - clean_logs: false - - - name: Update latest.yml after signing (NSIS) - if: matrix.os == 'windows-latest' && matrix.name == 'nsis' - run: | - $exeFile = "dist/Topluyo-Setup-${{ steps.package-version.outputs.version }}.exe" - $version = "${{ steps.package-version.outputs.version }}" - - # İmzalanmış dosyanın yeni SHA512 değerini hesapla - $fileHash = Get-FileHash -Path $exeFile -Algorithm SHA512 - # Hex string'i byte array'e çevir ve sonra Base64'e çevir - $hexBytes = [byte[]] -split ($fileHash.Hash -replace '..', '0x$& ') - $sha512 = [System.Convert]::ToBase64String($hexBytes) - - # Dosya boyutunu al - $fileSize = (Get-Item $exeFile).Length - - # Yeni latest.yml içeriğini oluştur - $currentDate = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") - $latestYml = "version: $version`n" + - "files:`n" + - " - url: Topluyo-Setup-$version.exe`n" + - " sha512: $sha512`n" + - " size: $fileSize`n" + - "path: Topluyo-Setup-$version.exe`n" + - "sha512: $sha512`n" + - "releaseDate: '$currentDate'" - - # latest.yml dosyasını güncelle (BOM olmadan UTF8) - [System.IO.File]::WriteAllText("dist/latest.yml", $latestYml, [System.Text.UTF8Encoding]::new($false)) - Write-Host "latest.yml updated with new SHA512: $sha512" - Write-Host "File size: $fileSize bytes" - shell: powershell + # # ✅ Windows için eSigner ile imzala - NSIS Installer + # - name: Sign NSIS Installer + # if: matrix.os == 'windows-latest' && matrix.name == 'nsis' + # uses: sslcom/esigner-codesign@develop + # with: + # command: sign + # username: ${{ secrets.ESIGNER_USERNAME }} + # password: ${{ secrets.ESIGNER_PASSWORD }} + # credential_id: ${{ secrets.ESIGNER_CREDENTIAL_ID }} + # totp_secret: ${{ secrets.ESIGNER_TOTP }} + # file_path: dist/Topluyo-Setup-${{ steps.package-version.outputs.version }}.exe + # malware_block: false + # override: true + # clean_logs: false + + # - name: Update latest.yml after signing (NSIS) + # if: matrix.os == 'windows-latest' && matrix.name == 'nsis' + # run: | + # $exeFile = "dist/Topluyo-Setup-${{ steps.package-version.outputs.version }}.exe" + # $version = "${{ steps.package-version.outputs.version }}" + # + # # İmzalanmış dosyanın yeni SHA512 değerini hesapla + # $fileHash = Get-FileHash -Path $exeFile -Algorithm SHA512 + # # Hex string'i byte array'e çevir ve sonra Base64'e çevir + # $hexBytes = [byte[]] -split ($fileHash.Hash -replace '..', '0x$& ') + # $sha512 = [System.Convert]::ToBase64String($hexBytes) + # + # # Dosya boyutunu al + # $fileSize = (Get-Item $exeFile).Length + # + # # Yeni latest.yml içeriğini oluştur + # $currentDate = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") + # $latestYml = "version: $version`n" + + # "files:`n" + + # " - url: Topluyo-Setup-$version.exe`n" + + # " sha512: $sha512`n" + + # " size: $fileSize`n" + + # "path: Topluyo-Setup-$version.exe`n" + + # "sha512: $sha512`n" + + # "releaseDate: '$currentDate'" + # + # # latest.yml dosyasını güncelle (BOM olmadan UTF8) + # [System.IO.File]::WriteAllText("dist/latest.yml", $latestYml, [System.Text.UTF8Encoding]::new($false)) + # Write-Host "latest.yml updated with new SHA512: $sha512" + # Write-Host "File size: $fileSize bytes" + # shell: powershell - name: Upload Build Artifacts uses: actions/upload-artifact@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 91da778..3e2ee36 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,11 +44,19 @@ jobs: python3 -m ensurepip --upgrade python3 -m pip install --upgrade pip setuptools + - name: Setup LXD for Snapcraft + if: matrix.os == 'ubuntu-latest' + uses: canonical/setup-lxd@v0.1.2 + with: + channel: latest/stable + - name: Install Linux build deps if: matrix.os == 'ubuntu-latest' run: | sudo apt-get update - sudo apt-get install -y libx11-dev libxext-dev libxtst-dev libxkbcommon-x11-dev libxkbfile-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxt-dev + sudo apt-get install -y libx11-dev libxext-dev libxtst-dev libxkbcommon-x11-dev libxkbfile-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxt-dev libpipewire-0.3-dev libpulse-dev + sudo snap install core22 + sudo snap install snapcraft --classic --channel=7.x/stable - name: Install dependencies run: npm install @@ -56,6 +64,11 @@ jobs: - name: Build Electron App shell: bash run: | + if [ "${{ matrix.name }}" = "nsis" ]; then + export WIN_CSC_LINK="${{ secrets.WIN_CERTS_BASE64 }}" + export WIN_CSC_KEY_PASSWORD="${{ secrets.WIN_CERTS_PASSWORD }}" + fi + if [ "${{ matrix.name }}" = "linux" ]; then npm run build:linux elif [ "${{ matrix.name }}" = "nsis" ]; then @@ -91,52 +104,52 @@ jobs: } shell: powershell - # ✅ Windows için eSigner ile imzala - NSIS Installer - - name: Sign NSIS Installer - if: matrix.os == 'windows-latest' && matrix.name == 'nsis' - uses: sslcom/esigner-codesign@develop - with: - command: sign - username: ${{ secrets.ESIGNER_USERNAME }} - password: ${{ secrets.ESIGNER_PASSWORD }} - credential_id: ${{ secrets.ESIGNER_CREDENTIAL_ID }} - totp_secret: ${{ secrets.ESIGNER_TOTP }} - file_path: dist/Topluyo-Setup-${{ steps.package-version.outputs.version }}.exe - malware_block: false - override: true - clean_logs: false - - - name: Update latest.yml after signing (NSIS) - if: matrix.os == 'windows-latest' && matrix.name == 'nsis' - run: | - $exeFile = "dist/Topluyo-Setup-${{ steps.package-version.outputs.version }}.exe" - $version = "${{ steps.package-version.outputs.version }}" - - # İmzalanmış dosyanın yeni SHA512 değerini hesapla - $fileHash = Get-FileHash -Path $exeFile -Algorithm SHA512 - # Hex string'i byte array'e çevir ve sonra Base64'e çevir - $hexBytes = [byte[]] -split ($fileHash.Hash -replace '..', '0x$& ') - $sha512 = [System.Convert]::ToBase64String($hexBytes) - - # Dosya boyutunu al - $fileSize = (Get-Item $exeFile).Length - - # Yeni latest.yml içeriğini oluştur - $currentDate = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") - $latestYml = "version: $version`n" + - "files:`n" + - " - url: Topluyo-Setup-$version.exe`n" + - " sha512: $sha512`n" + - " size: $fileSize`n" + - "path: Topluyo-Setup-$version.exe`n" + - "sha512: $sha512`n" + - "releaseDate: '$currentDate'" - - # latest.yml dosyasını güncelle (BOM olmadan UTF8) - [System.IO.File]::WriteAllText("dist/latest.yml", $latestYml, [System.Text.UTF8Encoding]::new($false)) - Write-Host "latest.yml updated with new SHA512: $sha512" - Write-Host "File size: $fileSize bytes" - shell: powershell + # # ✅ Windows için eSigner ile imzala - NSIS Installer + # - name: Sign NSIS Installer + # if: matrix.os == 'windows-latest' && matrix.name == 'nsis' + # uses: sslcom/esigner-codesign@develop + # with: + # command: sign + # username: ${{ secrets.ESIGNER_USERNAME }} + # password: ${{ secrets.ESIGNER_PASSWORD }} + # credential_id: ${{ secrets.ESIGNER_CREDENTIAL_ID }} + # totp_secret: ${{ secrets.ESIGNER_TOTP }} + # file_path: dist/Topluyo-Setup-${{ steps.package-version.outputs.version }}.exe + # malware_block: false + # override: true + # clean_logs: false + + # - name: Update latest.yml after signing (NSIS) + # if: matrix.os == 'windows-latest' && matrix.name == 'nsis' + # run: | + # $exeFile = "dist/Topluyo-Setup-${{ steps.package-version.outputs.version }}.exe" + # $version = "${{ steps.package-version.outputs.version }}" + # + # # İmzalanmış dosyanın yeni SHA512 değerini hesapla + # $fileHash = Get-FileHash -Path $exeFile -Algorithm SHA512 + # # Hex string'i byte array'e çevir ve sonra Base64'e çevir + # $hexBytes = [byte[]] -split ($fileHash.Hash -replace '..', '0x$& ') + # $sha512 = [System.Convert]::ToBase64String($hexBytes) + # + # # Dosya boyutunu al + # $fileSize = (Get-Item $exeFile).Length + # + # # Yeni latest.yml içeriğini oluştur + # $currentDate = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") + # $latestYml = "version: $version`n" + + # "files:`n" + + # " - url: Topluyo-Setup-$version.exe`n" + + # " sha512: $sha512`n" + + # " size: $fileSize`n" + + # "path: Topluyo-Setup-$version.exe`n" + + # "sha512: $sha512`n" + + # "releaseDate: '$currentDate'" + # + # # latest.yml dosyasını güncelle (BOM olmadan UTF8) + # [System.IO.File]::WriteAllText("dist/latest.yml", $latestYml, [System.Text.UTF8Encoding]::new($false)) + # Write-Host "latest.yml updated with new SHA512: $sha512" + # Write-Host "File size: $fileSize bytes" + # shell: powershell - name: Delete builder-debug.yml cross-platform shell: pwsh diff --git a/ScreenShare.html b/ScreenShare.html index d4b6cb0..6f3664c 100644 --- a/ScreenShare.html +++ b/ScreenShare.html @@ -299,10 +299,13 @@

Ekranını Paylaş

@@ -313,6 +316,23 @@

Ekranını Paylaş

async function initialize() { allSources = await window.stream.getSources(); renderSources(); + + try { + const status = await window.stream.isNativeAudioAvailable(); + const warningEl = document.getElementById("audio-warning"); + + if (!status.available) { + warningEl.style.display = "block"; + warningEl.style.color = "#ff4d4f"; + warningEl.innerText = "⚠️ Sistem uyumlu değil, ses yankı yapabilir."; + } else if (status.backend) { + warningEl.style.display = "block"; + warningEl.style.color = "#52c41a"; + warningEl.innerText = `✅ Ses İzolasyonu Aktif (${status.backend})`; + } + } catch (err) { + console.error("isNativeAudioAvailable failed:", err); + } } function renderSources() { diff --git a/Windows.js b/Windows.js index 13c0ace..2ad1caa 100644 --- a/Windows.js +++ b/Windows.js @@ -30,8 +30,8 @@ function createMainWindow(windowstate, url) { icon: path.join(__dirname, "topluyo.png"), webPreferences: { devTools: process.env.NODE_ENV === "development", - contextIsolation: false, - nodeIntegration: true, + contextIsolation: true, + nodeIntegration: false, nodeIntegrationInSubFrames: true, preload: path.join(__dirname, "preloads/main.js"), }, diff --git a/electron-builder.config.js b/electron-builder.config.js index 89e8c1f..dc0b05c 100644 --- a/electron-builder.config.js +++ b/electron-builder.config.js @@ -76,7 +76,9 @@ const config = { "maintainer": "Hasan Delibaş " }, "snap": { + "base": "core22", "confinement": "classic", + "useTemplateApp": false, "publish": false }, "mac": { diff --git a/main.js b/main.js index d3c28f1..6aeda52 100644 --- a/main.js +++ b/main.js @@ -144,6 +144,10 @@ if (!gotLock) { } app.whenReady().then(() => { + // Cloudflare vb. bot korumalarını aşmak için User-Agent'tan Electron ve uygulama adını temizliyoruz + const { session } = require("electron"); + app.userAgentFallback = session.defaultSession.getUserAgent().replace(/Electron\/\S+\s?/, "").replace(/topluyo\/\S+\s?/, ""); + //* Load the previous state with fallback to defaults const mainWindowState = windowStateKeeper({ defaultWidth: 800, @@ -656,6 +660,13 @@ ipcMain.on("close", () => { if (win && !win.isDestroyed()) win.close(); }); +ipcMain.handle("isNativeAudioAvailable", () => { + if (!captureModule) return { available: false, backend: null }; + const available = captureModule.isAvailable ? captureModule.isAvailable() : false; + const backend = captureModule.getLinuxAudioBackend ? captureModule.getLinuxAudioBackend() : null; + return { available, backend }; +}); + ipcMain.handle("start-native-audio", (event) => { const sourceId = global.lastSelectedSource || ""; console.log("start-native-audio invoked. Selected source:", sourceId); diff --git a/package-lock.json b/package-lock.json index bb840fd..c0674c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,16 @@ { "name": "topluyo", - "version": "2026.7.623", + "version": "2026.7.1018", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "topluyo", - "version": "2026.7.623", + "version": "2026.7.1018", "license": "MIT", "dependencies": { "electron-log": "^5.4.1", - "electron-native-screenshare": "1.1.0", + "electron-native-screenshare": "1.2.0", "electron-updater": "^6.3.9", "electron-window-state": "^5.0.3", "uiohook-napi": "^1.5.5" @@ -21,9 +21,9 @@ } }, "node_modules/@electron-internal/extract-zip": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@electron-internal/extract-zip/-/extract-zip-1.0.4.tgz", - "integrity": "sha512-Zr1Vs7E9tpCNhZHDAbFVXc2gEVCG9RqPDjrno5+bdgB6LRAuvgyMHJut4NCVyYwtAieapMzc3fiQ3CSTi75ARg==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@electron-internal/extract-zip/-/extract-zip-1.0.5.tgz", + "integrity": "sha512-+bqFCP98pLI0Tt0XQo1TmlXtwjWchISndDOxCkEcIuUgXWpBnLyRI+2DU+mesvnMMX6L1XDqYNA0lXNDHd/yiA==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -56,9 +56,9 @@ "license": "MIT" }, "node_modules/@electron/asar/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "dev": true, "license": "MIT", "dependencies": { @@ -124,9 +124,9 @@ } }, "node_modules/@electron/get": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-5.0.0.tgz", - "integrity": "sha512-pjoBpru1KdEtcExBnuHAP1cAc/5faoedw0hzJkL3o4/IJp7HNF1+fbrdxT3gMYRX2oJfvnA/WXeCTVQpYYxyJA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-5.1.0.tgz", + "integrity": "sha512-3kSBtG8ObcTVfXanm5vVJ6UnBLEVmVsRk1M+vGqCuMBV+XLCbJYuWQful+yIy0GQDsSlK0kHEriEHn7SPk4EnA==", "dev": true, "license": "MIT", "dependencies": { @@ -224,9 +224,9 @@ } }, "node_modules/@electron/rebuild": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-4.1.0.tgz", - "integrity": "sha512-GFky+1JeO8fpSqtZCh+2wFRN/MVbAhm7tXI2M7BA1Os79OR8LEoxRtAbRPyxvmKWhEMF/p10rNJkkgP1klI13g==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-4.2.0.tgz", + "integrity": "sha512-RKL/O+jGoXJMxrx/5771y1n0xTKmFuOYGO3gMmwypBM6rsH0kou0mswwdXA2JrhIkE4xyC7v9vGk0n6NPzgOxQ==", "dev": true, "license": "MIT", "dependencies": { @@ -271,9 +271,9 @@ "license": "MIT" }, "node_modules/@electron/universal/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", "dev": true, "license": "MIT", "dependencies": { @@ -281,9 +281,9 @@ } }, "node_modules/@electron/universal/node_modules/fs-extra": { - "version": "11.3.6", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", - "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.0.tgz", + "integrity": "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==", "dev": true, "license": "MIT", "dependencies": { @@ -324,6 +324,60 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@electron/windows-sign": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@electron/windows-sign/-/windows-sign-1.2.2.tgz", + "integrity": "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "peer": true, + "dependencies": { + "cross-dirname": "^0.1.0", + "debug": "^4.3.4", + "fs-extra": "^11.1.1", + "minimist": "^1.2.8", + "postject": "^1.0.0-alpha.6" + }, + "bin": { + "electron-windows-sign": "bin/electron-windows-sign.js" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/windows-sign/node_modules/fs-extra": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.0.tgz", + "integrity": "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/windows-sign/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/@isaacs/fs-minipass": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", @@ -406,9 +460,9 @@ } }, "node_modules/@noble/hashes": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", - "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.3.0.tgz", + "integrity": "sha512-oN+QwyX7VSHotibwubG3kpzbwKrfnyR6OOO+3Nk/53ADL7FmgHHz4TgrbaYKvvOw09u6QTx0oiH1cNCIOuN0CQ==", "dev": true, "license": "MIT", "engines": { @@ -554,9 +608,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.13.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.2.tgz", - "integrity": "sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==", + "version": "24.13.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz", + "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==", "dev": true, "license": "MIT", "dependencies": { @@ -909,16 +963,16 @@ "optional": true }, "node_modules/brace-expansion": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", - "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" } }, "node_modules/buffer-from": { @@ -1165,6 +1219,15 @@ "dev": true, "license": "MIT" }, + "node_modules/cross-dirname": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz", + "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1334,9 +1397,9 @@ "license": "MIT" }, "node_modules/dir-compare/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "dev": true, "license": "MIT", "dependencies": { @@ -1441,9 +1504,9 @@ } }, "node_modules/electron": { - "version": "43.0.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-43.0.0.tgz", - "integrity": "sha512-PV60GsWU6qufhuOhw3n+Yix3WPDcqDtBqE8orbEQGQGHEkgp9o/JCPgb7L4vIL0r1HnfPdqSRtboOTqbDkcFDQ==", + "version": "43.3.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-43.3.0.tgz", + "integrity": "sha512-nLlvu0WFjftWsSaTkV2B/c4NDuJBspTyXu8vKSQ6vLvFt8uG3NgN49LLKcXddwX0GqVvAQDhciWp+4xOdTdhew==", "dev": true, "license": "MIT", "dependencies": { @@ -1508,9 +1571,9 @@ } }, "node_modules/electron-native-screenshare": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/electron-native-screenshare/-/electron-native-screenshare-1.1.0.tgz", - "integrity": "sha512-NRsrOhveT1uIQMoBJVnHqWE/jKbQ/RUD7khKgvntMtAiM5uHtcmirFnhsToEwcwd1S0Ir5dzq+pLV0u2B2Lxsg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/electron-native-screenshare/-/electron-native-screenshare-1.2.0.tgz", + "integrity": "sha512-O7m+/AeE0UWFq8Z18THGSrPHRIxYiYtjdMKtVhGcNRE/sUN6Fj9EgXDOmmJnORCh303NWaNgmAnNz+JbeLa48Q==", "hasInstallScript": true, "license": "MIT", "os": [ @@ -1766,9 +1829,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz", - "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", "dev": true, "funding": [ { @@ -1818,9 +1881,9 @@ "license": "MIT" }, "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", "dev": true, "license": "MIT", "dependencies": { @@ -1995,9 +2058,9 @@ "license": "MIT" }, "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "dev": true, "license": "MIT", "dependencies": { @@ -2316,9 +2379,9 @@ } }, "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", "funding": [ { "type": "github", @@ -2511,13 +2574,13 @@ } }, "node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.5" + "brace-expansion": "^5.0.8" }, "engines": { "node": "18 || 20 || >=22" @@ -2577,9 +2640,9 @@ "license": "MIT" }, "node_modules/node-abi": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-4.32.0.tgz", - "integrity": "sha512-2cvOMwK7aQ8eQhHTG9DBK/akKfNaJDwtbxgUaA1u3BHGpd6cbUvWCbA0u3aKan+s7Nl60tMGx4tn11+VS1fiUA==", + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-4.33.0.tgz", + "integrity": "sha512-vLBWCKb+7LWsX+TbfzWOkw0W81m377tyx3hOweBTjO43CXZnRGS1/JPWs20fr0PgZyDXk6ROYrylsEycK8raDA==", "dev": true, "license": "MIT", "dependencies": { @@ -2662,9 +2725,9 @@ } }, "node_modules/node-gyp/node_modules/undici": { - "version": "6.27.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz", - "integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==", + "version": "6.28.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz", + "integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==", "dev": true, "license": "MIT", "engines": { @@ -2813,9 +2876,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "dev": true, "license": "MIT", "engines": { @@ -2871,6 +2934,36 @@ "node": ">=10.4.0" } }, + "node_modules/postject": { + "version": "1.0.0-alpha.6", + "resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz", + "integrity": "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "commander": "^9.4.0" + }, + "bin": { + "postject": "dist/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/postject/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, "node_modules/proc-log": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", @@ -2946,9 +3039,9 @@ } }, "node_modules/pvutils": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", - "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.2.0.tgz", + "integrity": "sha512-BbubeCEyTuQjVMakvJQ/Sxbc93F2pwmbsxONT/ZRrwU7Ua38d8unYTwXpTVLAKJ4BDuH9IGztCjQcd/N/39Dvg==", "dev": true, "license": "MIT", "engines": { @@ -3117,9 +3210,9 @@ } }, "node_modules/sax": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", - "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", "license": "BlueOak-1.0.0", "engines": { "node": ">=11.0.0" @@ -3310,9 +3403,9 @@ } }, "node_modules/tar": { - "version": "7.5.19", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.19.tgz", - "integrity": "sha512-4LeEWl96twnS2Q7Bz4MGqgazLqO+hJN63GZxXoIqh1T3VweYD997gbU1ItNsQafqqXTXd5WFyFdReLtwvRBNiw==", + "version": "7.5.22", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz", + "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -3470,9 +3563,9 @@ } }, "node_modules/undici": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", - "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", + "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", "dev": true, "license": "MIT", "optional": true, diff --git a/package.json b/package.json index 87dc1f0..725df0c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "topluyo", - "version": "2026.7.1018", + "desktopName": "Topluyo", + "version": "2026.8.1616", "description": "Topluyo", "main": "main.js", "scripts": { @@ -25,7 +26,7 @@ }, "dependencies": { "electron-log": "^5.4.1", - "electron-native-screenshare": "1.1.0", + "electron-native-screenshare": "1.2.0", "electron-updater": "^6.3.9", "electron-window-state": "^5.0.3", "uiohook-napi": "^1.5.5" @@ -114,7 +115,9 @@ "maintainer": "Hasan Delibaş " }, "snap": { + "base": "core22", "confinement": "classic", + "useTemplateApp": false, "publish": false }, "mac": { @@ -147,7 +150,7 @@ ] }, "allowScripts": { - "electron-native-screenshare@1.0.1": true, + "electron-native-screenshare@1.2.0": true, "electron-winstaller@5.4.0": true, "uiohook-napi@1.5.5": true } diff --git a/preloads/loading.js b/preloads/loading.js index b270252..52fba12 100644 --- a/preloads/loading.js +++ b/preloads/loading.js @@ -1,9 +1,8 @@ // preloads/loading.js -const { ipcRenderer } = require("electron"); +const { ipcRenderer, contextBridge } = require("electron"); window.addEventListener("DOMContentLoaded", () => { - window.closeWindow = () => { - ipcRenderer.send("close"); - }; document.body.classList.add("electron-app"); }); + +contextBridge.exposeInMainWorld("closeWindow", () => ipcRenderer.send("close")); diff --git a/preloads/main.js b/preloads/main.js index 9321f0c..b6b15fc 100644 --- a/preloads/main.js +++ b/preloads/main.js @@ -1,256 +1,250 @@ // preloads/main.js -const { ipcRenderer, contextBridge } = require("electron"); +const { ipcRenderer, contextBridge, webFrame } = require("electron"); window.addEventListener("DOMContentLoaded", () => { - window.closeWindow = () => { - ipcRenderer.send("close"); - }; + document.body.classList.add("electron-app"); + document.body.classList.add("Electron"); +}); - window.minimizeWindow = () => { - ipcRenderer.send("minimize"); - }; - window.maximizeWindow = () => { - ipcRenderer.send("maximize"); - }; +// Expose standard window controls +contextBridge.exposeInMainWorld("closeWindow", () => ipcRenderer.send("close")); +contextBridge.exposeInMainWorld("minimizeWindow", () => ipcRenderer.send("minimize")); +contextBridge.exposeInMainWorld("maximizeWindow", () => ipcRenderer.send("maximize")); +contextBridge.exposeInMainWorld("ossOpen", () => ipcRenderer.send("open-oss")); - window.ossOpen = () => { - ipcRenderer.send("open-oss"); - }; +contextBridge.exposeInMainWorld("stream", { + getSources: () => ipcRenderer.invoke("getSources"), + setSource: (data) => + ipcRenderer.invoke("setSource", { id: data.id, isAudioEnabled: data.audio }), +}); - document.body.classList.add("electron-app"); - document.body.classList.add("Electron"); +contextBridge.exposeInMainWorld("Electron", { + onUpdateMessage: (callback) => ipcRenderer.on("update-message", (e, msg) => callback({}, msg)), + onProgress: (callback) => ipcRenderer.on("download-progress", (e, obj) => callback({}, obj)), + getOSSLibraries: () => ipcRenderer.invoke("get-oss-libraries"), + openExternal: (url) => ipcRenderer.invoke("open-external", url), + SetPTTKey: (key) => ipcRenderer.invoke("set-ptt-key", key), + NotificationIFRAME: (iframeUrl, force = false) => ipcRenderer.send('notification:iframe', { iframeUrl, force }), + NotificationOS: (obj) => ipcRenderer.send('notification:os', obj), + version: ipcRenderer.sendSync('get-app-version-sync'), + setStartup: (checked) => ipcRenderer.send("set-Startup", checked) +}); - if (typeof documenter !== 'undefined') { - documenter.on("input", "#run-on-startup", function () { - ipcRenderer.send("set-Startup", this.checked); - }); +// IPC for Native Audio Capture +contextBridge.exposeInMainWorld("nativeAudioIPC", { + start: () => ipcRenderer.invoke('start-native-audio'), + stop: () => ipcRenderer.invoke('stop-native-audio'), + onData: (callback) => { + ipcRenderer.removeAllListeners('native-audio-data'); + ipcRenderer.on('native-audio-data', (event, buffer, meta) => callback(buffer, meta)); + }, + offData: () => ipcRenderer.removeAllListeners('native-audio-data') +}); + +// Setup webFrame injections for callbacks that require global variables +ipcRenderer.on("electron-error", (event, errorData) => { + let osInfo = `${errorData.os} ${errorData.osRelease} (${errorData.arch})`; + if (errorData.os === 'win32') { + osInfo += errorData.isWindowsStore ? ' [Microsoft Store]' : ' [Stand-alone]'; } + const extraInfo = errorData.extra ? `\nExtra: ${errorData.extra}` : ''; - ipcRenderer.on("electron-error", (event, errorData) => { - let osInfo = `${errorData.os} ${errorData.osRelease} (${errorData.arch})`; - if (errorData.os === 'win32') { - osInfo += errorData.isWindowsStore ? ' [Microsoft Store]' : ' [Stand-alone]'; - } - - const extraInfo = errorData.extra ? `\nExtra: ${errorData.extra}` : ''; - - const errorText = `**Desktop App Error** -Type: ${errorData.type} -Message: ${errorData.message} -OS: ${osInfo} -App Version: ${errorData.appVersion} -Electron: ${errorData.electronVersion}${extraInfo} -Stack: -\`\`\` -${errorData.stack || 'No stack trace'} -\`\`\``.substring(0, 3000); + const errorText = `**Desktop App Error**\nType: ${errorData.type}\nMessage: ${errorData.message}\nOS: ${osInfo}\nApp Version: ${errorData.appVersion}\nElectron: ${errorData.electronVersion}${extraInfo}\nStack:\n\`\`\`\n${errorData.stack || 'No stack trace'}\n\`\`\``.substring(0, 3000); + webFrame.executeJavaScript(` if (typeof Route !== 'undefined' && Route.api) { - Route.api({ - api: "/!api/post/add", - data: { channel_id: 33591, code: "", text: errorText } - }); + Route.api({ api: "/!api/post/add", data: { channel_id: 33591, code: "", text: ${JSON.stringify(errorText)} } }); } else if (window.Route && window.Route.api) { - window.Route.api({ - api: "/!api/post/add", - data: { channel_id: 33591, code: "", text: errorText } - }); + window.Route.api({ api: "/!api/post/add", data: { channel_id: 33591, code: "", text: ${JSON.stringify(errorText)} } }); } - }); + `).catch(console.error); +}); - ipcRenderer.on("ptt-status-change", (event, status) => { +ipcRenderer.on("ptt-status-change", (event, status) => { + webFrame.executeJavaScript(` if (typeof Topluyo !== 'undefined' && typeof Topluyo.Microphone === 'function') { - Topluyo.Microphone(status); + Topluyo.Microphone(${status}); } else if (window.Topluyo && typeof window.Topluyo.Microphone === 'function') { - window.Topluyo.Microphone(status); + window.Topluyo.Microphone(${status}); } - }); + `).catch(console.error); +}); - // Notification Response Listener - ipcRenderer.on('notification:response', (event, obj) => { +ipcRenderer.on('notification:response', (event, obj) => { + webFrame.executeJavaScript(` if (typeof Topluyo !== 'undefined' && typeof Topluyo.NotificationResponse === 'function') { - Topluyo.NotificationResponse(obj); + Topluyo.NotificationResponse(${JSON.stringify(obj)}); } else if (window.Topluyo && typeof window.Topluyo.NotificationResponse === 'function') { - window.Topluyo.NotificationResponse(obj); + window.Topluyo.NotificationResponse(${JSON.stringify(obj)}); } - }); + `).catch(console.error); }); -// Override MediaDevices.prototype to ensure we catch ALL calls in this frame -if (typeof MediaDevices !== 'undefined' && MediaDevices.prototype.getDisplayMedia) { - const originalGetDisplayMedia = MediaDevices.prototype.getDisplayMedia; - MediaDevices.prototype.getDisplayMedia = async function (constraints) { - console.log("[NativeCapture] getDisplayMedia intercepted! Constraints:", constraints); - - // Call the original Electron implementation - const stream = await originalGetDisplayMedia.call(this, constraints); - - const audioTracks = stream.getAudioTracks(); - console.log("[NativeCapture] Original stream audio tracks:", audioTracks.length); - - if (audioTracks.length > 0) { - console.log("[NativeCapture] Requesting WASAPI start from main process..."); - try { - const started = await ipcRenderer.invoke('start-native-audio'); - console.log("[NativeCapture] WASAPI start response:", started); - - if (started && started.platform === 'linux') { - console.log("[NativeCapture] PulseAudio Linux routing started:", started.sinkName); - audioTracks[0].stop(); - stream.removeTrack(audioTracks[0]); - - try { - const paStream = await navigator.mediaDevices.getUserMedia({ - audio: { - deviceId: started.sinkName - } - }); - const paAudioTrack = paStream.getAudioTracks()[0]; - - const stopNativeCapture = () => { - console.log("[NativeCapture] Stopping Linux capture..."); - ipcRenderer.invoke('stop-native-audio'); - paAudioTrack.stop(); - }; - - const originalTrackStop = paAudioTrack.stop.bind(paAudioTrack); - paAudioTrack.stop = () => { - stopNativeCapture(); - originalTrackStop(); - }; - - const videoTracks = stream.getVideoTracks(); - if (videoTracks.length > 0) { - videoTracks[0].addEventListener('ended', () => { - stopNativeCapture(); - }); - } - - stream.addTrack(paAudioTrack); - console.log("[NativeCapture] Added PulseAudio virtual track to stream!"); - } catch (e) { - console.error("[NativeCapture] Failed to capture PulseAudio sink via getUserMedia:", e); - } - } else if (started) { - console.log("[NativeCapture] Native WASAPI started successfully. Stopping default loopback track to prevent echo."); - audioTracks[0].stop(); - stream.removeTrack(audioTracks[0]); - - console.log("[NativeCapture] Creating WebCodecs MediaStreamTrackGenerator."); - const generator = new MediaStreamTrackGenerator({ kind: 'audio' }); - const writer = generator.writable.getWriter(); - - let timestamp = 0; // Microseconds - let packetCount = 0; - - ipcRenderer.removeAllListeners('native-audio-data'); - ipcRenderer.on('native-audio-data', (event, buffer, meta) => { +// Documenter logic injection +webFrame.executeJavaScript(` + if (typeof documenter !== 'undefined') { + documenter.on("input", "#run-on-startup", function () { + if (window.Electron && window.Electron.setStartup) { + window.Electron.setStartup(this.checked); + } + }); + } +`).catch(e => { }); + +// Inject MediaDevices override synchronously into the main world using a script tag +const injectScript = document.createElement('script'); +injectScript.textContent = ` + try { + const patchMediaDevices = () => { + const mediaDevicesProto = Object.getPrototypeOf(navigator.mediaDevices) || MediaDevices.prototype; + if (mediaDevicesProto && mediaDevicesProto.getDisplayMedia && !navigator.mediaDevices.__isNativeCapturePatched) { + navigator.mediaDevices.__isNativeCapturePatched = true; + + const originalGetDisplayMedia = mediaDevicesProto.getDisplayMedia; + mediaDevicesProto.getDisplayMedia = async function (constraints) { + + const stream = await originalGetDisplayMedia.call(this, constraints); + const audioTracks = stream.getAudioTracks(); + + if (audioTracks.length > 0) { try { - packetCount++; - if (packetCount % 100 === 0) { - console.log(`[NativeCapture] Received 100 audio packets. Latest meta:`, meta, `Buffer size: ${buffer.byteLength}`); - } - - const arrayBuffer = buffer.buffer || buffer; - const byteOffset = buffer.byteOffset || 0; - const byteLength = buffer.byteLength || buffer.length; - - const isFloat = meta.isFloat; - let typedData; - - if (isFloat) { - typedData = new Float32Array(arrayBuffer, byteOffset, byteLength / 4); - } else { - typedData = new Int16Array(arrayBuffer, byteOffset, byteLength / 2); + const started = await window.nativeAudioIPC.start(); + + if (started && started.platform === 'linux') { + audioTracks[0].stop(); + stream.removeTrack(audioTracks[0]); + + try { + const paStream = await navigator.mediaDevices.getUserMedia({ + audio: { deviceId: started.sinkName } + }); + const paAudioTrack = paStream.getAudioTracks()[0]; + + const stopNativeCapture = () => { + window.nativeAudioIPC.stop(); + paAudioTrack.stop(); + }; + + const originalTrackStop = paAudioTrack.stop.bind(paAudioTrack); + paAudioTrack.stop = () => { + stopNativeCapture(); + originalTrackStop(); + }; + + const videoTracks = stream.getVideoTracks(); + if (videoTracks.length > 0) { + videoTracks[0].addEventListener('ended', stopNativeCapture); + } + + stream.addTrack(paAudioTrack); + } catch (e) { + console.error("[NativeCapture] Failed to capture PulseAudio sink via getUserMedia:", e); + } + } else if (started) { + audioTracks[0].stop(); + stream.removeTrack(audioTracks[0]); + + const generator = new MediaStreamTrackGenerator({ kind: 'audio' }); + const writer = generator.writable.getWriter(); + + let timestamp = 0; // Microseconds + let packetCount = 0; + + window.nativeAudioIPC.onData((buffer, meta) => { + try { + packetCount++; + + const arrayBuffer = buffer.buffer || buffer; + const byteOffset = buffer.byteOffset || 0; + const byteLength = buffer.byteLength || buffer.length; + + const isFloat = meta.isFloat; + let typedData; + + if (isFloat) { + typedData = new Float32Array(arrayBuffer, byteOffset, byteLength / 4); + } else { + typedData = new Int16Array(arrayBuffer, byteOffset, byteLength / 2); + } + + const frames = typedData.length / meta.channels; + + const audioData = new AudioData({ + format: isFloat ? 'f32' : 's16', + sampleRate: meta.sampleRate, + numberOfFrames: frames, + numberOfChannels: meta.channels, + timestamp: timestamp, + data: typedData + }); + + timestamp += (frames / meta.sampleRate) * 1000000; + writer.write(audioData); + } catch (e) { + console.error("[NativeCapture] Audio insertion error:", e); + } + }); + + const stopNativeCapture = () => { + window.nativeAudioIPC.stop(); + window.nativeAudioIPC.offData(); + }; + + const originalGeneratorStop = generator.stop.bind(generator); + generator.stop = () => { + stopNativeCapture(); + originalGeneratorStop(); + }; + + const videoTracks = stream.getVideoTracks(); + if (videoTracks.length > 0) { + videoTracks[0].addEventListener('ended', () => { + stopNativeCapture(); + }); + } + + stream.addTrack(generator); } - - const frames = typedData.length / meta.channels; - - const audioData = new AudioData({ - format: isFloat ? 'f32' : 's16', - sampleRate: meta.sampleRate, - numberOfFrames: frames, - numberOfChannels: meta.channels, - timestamp: timestamp, - data: typedData - }); - - timestamp += (frames / meta.sampleRate) * 1000000; - writer.write(audioData); - } catch (e) { - console.error("[NativeCapture] Audio insertion error:", e); + } catch (err) { + console.error("[NativeCapture] IPC error during native capture start:", err); } - }); - - // Hook stopping mechanism - const stopNativeCapture = () => { - console.log("[NativeCapture] Stopping WASAPI capture..."); - ipcRenderer.invoke('stop-native-audio'); - ipcRenderer.removeAllListeners('native-audio-data'); - }; - - const originalGeneratorStop = generator.stop.bind(generator); - generator.stop = () => { - stopNativeCapture(); - originalGeneratorStop(); - }; - - const videoTracks = stream.getVideoTracks(); - if (videoTracks.length > 0) { - videoTracks[0].addEventListener('ended', () => { - console.log("[NativeCapture] Video track ended, stopping audio."); - stopNativeCapture(); - }); } - - stream.addTrack(generator); - console.log("[NativeCapture] Added native audio track to stream!"); - } else { - console.log("[NativeCapture] Native capture returned false. Falling back to default Electron loopback."); - } - } catch (err) { - console.error("[NativeCapture] IPC error during native capture start:", err); - console.log("[NativeCapture] Falling back to default Electron loopback."); + return stream; + }; } + }; + + if (navigator.mediaDevices) { + patchMediaDevices(); + } else { + let attempts = 0; + const patchInterval = setInterval(() => { + attempts++; + if (navigator.mediaDevices) { + patchMediaDevices(); + clearInterval(patchInterval); + } else if (attempts > 100) { + clearInterval(patchInterval); + } + }, 50); + } + } catch (err) { + console.error("[NativeCapture] Error during synchronous injection:", err); + } +`; + +// Inject into the DOM synchronously before other scripts load +if (document.documentElement) { + document.documentElement.appendChild(injectScript); + injectScript.remove(); +} else { + // Use MutationObserver to inject as soon as documentElement is available, before page scripts + const observer = new MutationObserver(() => { + if (document.documentElement) { + document.documentElement.appendChild(injectScript); + injectScript.remove(); + observer.disconnect(); } - - return stream; - }; -} - -try { - contextBridge.exposeInMainWorld("stream", { - getSources: () => ipcRenderer.invoke("getSources"), - setSource: (data) => - ipcRenderer.invoke("setSource", { id: data.id, isAudioEnabled: data.audio }), - }); - - contextBridge.exposeInMainWorld("Electron", { - onUpdateMessage: (callback) => ipcRenderer.on("update-message", callback), - onProgress: (callback) => ipcRenderer.on("download-progress", callback), - getOSSLibraries: () => ipcRenderer.invoke("get-oss-libraries"), - openExternal: (url) => ipcRenderer.invoke("open-external", url), - SetPTTKey: (key) => ipcRenderer.invoke("set-ptt-key", key), - NotificationIFRAME: (iframeUrl, force = false) => ipcRenderer.send('notification:iframe', { iframeUrl, force }), - NotificationOS: (obj) => ipcRenderer.send('notification:os', obj), - version: ipcRenderer.sendSync('get-app-version-sync') }); -} catch (e) { - // If contextIsolation is false, expose directly to window - window.stream = { - getSources: () => ipcRenderer.invoke("getSources"), - setSource: (data) => - ipcRenderer.invoke("setSource", { id: data.id, isAudioEnabled: data.audio }), - }; - window.Electron = { - ...(window.Electron || {}), - onUpdateMessage: (callback) => ipcRenderer.on("update-message", callback), - onProgress: (callback) => ipcRenderer.on("download-progress", callback), - getOSSLibraries: () => ipcRenderer.invoke("get-oss-libraries"), - openExternal: (url) => ipcRenderer.invoke("open-external", url), - SetPTTKey: (key) => ipcRenderer.invoke("set-ptt-key", key), - NotificationIFRAME: (iframeUrl, force = false) => ipcRenderer.send('notification:iframe', { iframeUrl, force }), - NotificationOS: (obj) => ipcRenderer.send('notification:os', obj), - version: ipcRenderer.sendSync('get-app-version-sync') - }; + observer.observe(document, { childList: true }); } diff --git a/preloads/notification.js b/preloads/notification.js index 823b7b6..fc53a71 100644 --- a/preloads/notification.js +++ b/preloads/notification.js @@ -4,10 +4,6 @@ const { ipcRenderer, contextBridge } = require("electron"); let isClosing = false; window.addEventListener("DOMContentLoaded", () => { - window.closeWindow = () => { - isClosing = true; - ipcRenderer.send("notification:close"); - }; document.body.classList.add("electron-app"); window.addEventListener("mousedown", () => { @@ -19,24 +15,16 @@ window.addEventListener("DOMContentLoaded", () => { }); }); -try { - contextBridge.exposeInMainWorld("NotificationClose", () => { - isClosing = true; - ipcRenderer.send('notification:close'); - }); - contextBridge.exposeInMainWorld("closeWindow", () => { - isClosing = true; - ipcRenderer.send('notification:close'); - }); - contextBridge.exposeInMainWorld("NotificationResponse", (obj) => ipcRenderer.send('notification:event', obj)); -} catch (e) { - window.NotificationClose = () => { - isClosing = true; - ipcRenderer.send('notification:close'); - }; - window.closeWindow = () => { - isClosing = true; - ipcRenderer.send('notification:close'); - }; - window.NotificationResponse = (obj) => ipcRenderer.send('notification:event', obj); -} +contextBridge.exposeInMainWorld("NotificationClose", () => { + isClosing = true; + ipcRenderer.send('notification:close'); +}); + +contextBridge.exposeInMainWorld("closeWindow", () => { + isClosing = true; + ipcRenderer.send('notification:close'); +}); + +contextBridge.exposeInMainWorld("NotificationResponse", (obj) => { + ipcRenderer.send('notification:event', obj); +}); diff --git a/preloads/oss.js b/preloads/oss.js index d2a1184..1fd4e6f 100644 --- a/preloads/oss.js +++ b/preloads/oss.js @@ -2,20 +2,12 @@ const { ipcRenderer, contextBridge } = require("electron"); window.addEventListener("DOMContentLoaded", () => { - window.closeWindow = () => { - ipcRenderer.send("close"); - }; document.body.classList.add("electron-app"); }); -try { - contextBridge.exposeInMainWorld("electronAPI", { - getOSSLibraries: () => ipcRenderer.invoke("get-oss-libraries"), - openExternal: (url) => ipcRenderer.invoke("open-external", url) - }); -} catch (e) { - window.electronAPI = { - getOSSLibraries: () => ipcRenderer.invoke("get-oss-libraries"), - openExternal: (url) => ipcRenderer.invoke("open-external", url) - }; -} +contextBridge.exposeInMainWorld("closeWindow", () => ipcRenderer.send("close")); + +contextBridge.exposeInMainWorld("electronAPI", { + getOSSLibraries: () => ipcRenderer.invoke("get-oss-libraries"), + openExternal: (url) => ipcRenderer.invoke("open-external", url) +}); diff --git a/preloads/screenshare.js b/preloads/screenshare.js index 13005dc..fd16be2 100644 --- a/preloads/screenshare.js +++ b/preloads/screenshare.js @@ -2,22 +2,14 @@ const { ipcRenderer, contextBridge } = require("electron"); window.addEventListener("DOMContentLoaded", () => { - window.closeWindow = () => { - ipcRenderer.send("close"); - }; document.body.classList.add("electron-app"); }); -try { - contextBridge.exposeInMainWorld("stream", { - getSources: () => ipcRenderer.invoke("getSources"), - setSource: (data) => - ipcRenderer.invoke("setSource", { id:data.id, isAudioEnabled:data.audio }), - }); -} catch (e) { - window.stream = { - getSources: () => ipcRenderer.invoke("getSources"), - setSource: (data) => - ipcRenderer.invoke("setSource", { id:data.id, isAudioEnabled:data.audio }), - }; -} +contextBridge.exposeInMainWorld("closeWindow", () => ipcRenderer.send("close")); + +contextBridge.exposeInMainWorld("stream", { + getSources: () => ipcRenderer.invoke("getSources"), + setSource: (data) => + ipcRenderer.invoke("setSource", { id:data.id, isAudioEnabled:data.audio }), + isNativeAudioAvailable: () => ipcRenderer.invoke("isNativeAudioAvailable"), +}); diff --git a/utils.js b/utils.js index 24af082..e0a6642 100644 --- a/utils.js +++ b/utils.js @@ -36,7 +36,13 @@ const getAllSources = async () => { } }; +let currentStreamWin = null; async function createStreamWindow(_, callback) { + if (currentStreamWin && !currentStreamWin.isDestroyed()) { + currentStreamWin.focus(); + return; + } + let callbackcalled = false; const win = new BrowserWindow({ width: 900, @@ -58,6 +64,7 @@ async function createStreamWindow(_, callback) { win.setAlwaysOnTop(true, "screen-saver"); } + currentStreamWin = win; win.loadFile("ScreenShare.html"); const allSources = await getAllSources(); @@ -93,15 +100,19 @@ async function createStreamWindow(_, callback) { win.on("close", () => { console.log("Stream penceresi kapatılıyor"); if (callbackcalled) return; + if (callbackcalled) { + currentStreamWin = null; + return; + } callbackcalled = true; try { ipcMain.removeHandler("getSources"); ipcMain.removeHandler("setSource"); callback(null); } catch (e) { - console.error("Pencere kapatma hatası:", e); - throw e; + console.error(e); } + currentStreamWin = null; }); } @@ -177,7 +188,13 @@ const openExternalLinks = (url) => { }; +let currentOssWin = null; function ossWindow(){ + if (currentOssWin && !currentOssWin.isDestroyed()) { + currentOssWin.focus(); + return; + } + let ossWin = new BrowserWindow({ width: 800, height: 600, @@ -197,8 +214,11 @@ function ossWindow(){ return { action: "deny" }; }) ossWin.on("closed", () => { + currentOssWin = null; ossWin = null; }); + + currentOssWin = ossWin; } module.exports = { isSafeUrl, mediaHandler, openExternalLinks, ossWindow };