feat(desktop): port v0.11.4-v0.15.2 from Tauri to Electron + Discord-parity audio (v0.16.0)

Chronological port of every Tauri release commit (v0.11.4 -> v0.15.2)
into the Electron rebuild, plus Discord-style audio handling that goes
beyond the Tauri original.

Highlights:
  - All 17 Tauri release commits ported (audio fixes, custom notification
    sound, Discord-style chat UX, profile banner, changelog page,
    Discord-parity call UX, screen-share echo + re-watch UX, audio-loop
    fix).
  - Native napi-rs audio-loopback addon with WASAPI process-loopback:
      * EXCLUDE_TARGET_PROCESS_TREE for full-screen shares -> peers
        never hear themselves echoed back through the capture.
      * INCLUDE_TARGET_PROCESS_TREE for window shares -> only the
        picked window's audio is captured, not the whole OS mixer
        (Discord parity).
      * HWND -> PID resolution via Win32 GetWindowThreadProcessId.
  - Discord-style screen-source picker (thumbnail grid, screens vs
    apps tabs, live-refreshing thumbnails).
  - Hash routing fix for packaged builds (file:// can't resolve
    BrowserRouter paths).
  - Tauri sources removed (apps/desktop/src-tauri).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
byGalax
2026-05-06 23:35:01 +02:00
parent 72d02e385f
commit 825160ee46
504 changed files with 14217 additions and 14366 deletions
+27 -33
View File
@@ -1,5 +1,3 @@
import { check as checkUpdate } from '@tauri-apps/plugin-updater';
import { isTauriRuntime } from './globalShortcut';
export interface UpdateState {
@@ -20,38 +18,34 @@ export const IDLE_UPDATE_STATE: UpdateState = {
error: null,
};
type UpdateHandle = Awaited<ReturnType<typeof checkUpdate>>;
let cachedUpdate: UpdateHandle | null = null;
// Module-local flag: main owns the real "pending update" state via
// electron-updater, but the renderer also needs to refuse installUpdate()
// calls that weren't preceded by a successful checkForUpdate().
let hasPendingUpdate = false;
export async function checkForUpdate(): Promise<UpdateState> {
if (!isTauriRuntime()) {
return { ...IDLE_UPDATE_STATE };
}
try {
const update = await checkUpdate();
if (!update) {
cachedUpdate = null;
const result = await window.electronAPI.checkForUpdate();
if (!result.available || !result.info) {
hasPendingUpdate = false;
return { ...IDLE_UPDATE_STATE };
}
cachedUpdate = update;
hasPendingUpdate = true;
return {
available: true,
version: update.version ?? null,
notes: update.body ?? null,
version: result.info.version ?? null,
notes: result.info.releaseNotes ?? null,
downloading: false,
downloaded: false,
error: null,
};
} catch (err: unknown) {
// Swallow "no release on GitHub yet" / network-unreachable cases silently.
// The updater endpoint serves `latest.json` from GitHub releases; a fresh
// repo or offline machine produces a generic "Could not fetch a valid
// release JSON" error that has no actionable information for the user —
// logging it on every launch just pollutes the console.
const msg = err instanceof Error ? err.message : String(err);
const benign =
/could not fetch a valid release json|network|timed? out|failed to fetch|connection/i.test(
/could not fetch a valid release json|network|timed? out|failed to fetch|connection|enotfound|econnreset|etimedout|404/i.test(
msg,
);
if (!benign) {
@@ -64,25 +58,25 @@ export async function checkForUpdate(): Promise<UpdateState> {
}
}
// Downloads + installs the previously checked update. On Windows the app
// quits during install (passive installer); on macOS/Linux tauri triggers
// a relaunch automatically.
// Downloads + installs the previously checked update. On Windows the
// app quits during install (passive installer); electron-updater
// triggers a relaunch on macOS/Linux.
export async function installUpdate(
onProgress?: (downloaded: number, total: number | null) => void,
): Promise<void> {
if (!cachedUpdate) {
if (!hasPendingUpdate) {
throw new Error('no pending update — call checkForUpdate() first');
}
let total: number | null = null;
let downloaded = 0;
await cachedUpdate.downloadAndInstall((event) => {
if (event.event === 'Started') {
total = event.data.contentLength ?? null;
downloaded = 0;
} else if (event.event === 'Progress') {
downloaded += event.data.chunkLength;
}
onProgress?.(downloaded, total);
});
cachedUpdate = null;
let unsub: (() => void) | null = null;
if (onProgress) {
unsub = window.electronAPI.onUpdaterProgress((p) => {
onProgress(p.transferred, p.total || null);
});
}
try {
await window.electronAPI.downloadInstallUpdate();
} finally {
unsub?.();
hasPendingUpdate = false;
}
}