parent
f5dffd3c82
commit
ebfe647cb1
@ -0,0 +1,64 @@ |
||||
/* |
||||
* SPDX-License-Identifier: GPL-3.0 |
||||
* Aerocord, a vesktop fork for older microsoft NT releases such as NT 6.0, 6.1, 6.2 and 6.3.
|
||||
* Credits to vendicated and the rest of the vesktop contribuitors for making Vesktop! |
||||
*/ |
||||
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs"; |
||||
import { dirname, join } from "path"; |
||||
import type { Settings as TSettings, State as TState } from "shared/settings"; |
||||
import { SettingsStore } from "shared/utils/SettingsStore"; |
||||
|
||||
import { DATA_DIR, VENCORD_SETTINGS_FILE } from "./constants"; |
||||
|
||||
const SETTINGS_FILE = join(DATA_DIR, "settings.json"); |
||||
const STATE_FILE = join(DATA_DIR, "state.json"); |
||||
|
||||
function loadSettings<T extends object = any>(file: string, name: string) { |
||||
let settings = {} as T; |
||||
try { |
||||
const content = readFileSync(file, "utf8"); |
||||
try { |
||||
settings = JSON.parse(content); |
||||
} catch (err) { |
||||
console.error(`Failed to parse ${name}.json:`, err); |
||||
} |
||||
} catch {} |
||||
|
||||
const store = new SettingsStore(settings); |
||||
store.addGlobalChangeListener(o => { |
||||
mkdirSync(dirname(file), { recursive: true }); |
||||
writeFileSync(file, JSON.stringify(o, null, 4)); |
||||
}); |
||||
|
||||
return store; |
||||
} |
||||
|
||||
export const Settings = loadSettings<TSettings>(SETTINGS_FILE, "Aerocord settings"); |
||||
if (Object.hasOwn(Settings.plain, "discordWindowsTitleBar")) { |
||||
Settings.plain.customTitleBar = Settings.plain.discordWindowsTitleBar; |
||||
delete Settings.plain.discordWindowsTitleBar; |
||||
Settings.markAsChanged(); |
||||
} |
||||
|
||||
export const VencordSettings = loadSettings<any>(VENCORD_SETTINGS_FILE, "Vencord settings"); |
||||
|
||||
if (Object.hasOwn(Settings.plain, "firstLaunch") && !existsSync(STATE_FILE)) { |
||||
console.warn("legacy state in settings.json detected. migrating to state.json"); |
||||
const state = {} as TState; |
||||
for (const prop of [ |
||||
"firstLaunch", |
||||
"maximized", |
||||
"minimized", |
||||
"skippedUpdate", |
||||
"steamOSLayoutVersion", |
||||
"windowBounds" |
||||
] as const) { |
||||
state[prop] = Settings.plain[prop]; |
||||
delete Settings.plain[prop]; |
||||
} |
||||
Settings.markAsChanged(); |
||||
writeFileSync(STATE_FILE, JSON.stringify(state, null, 4)); |
||||
} |
||||
|
||||
export const State = loadSettings<TState>(STATE_FILE, "Vesktop state"); |
@ -0,0 +1,39 @@ |
||||
/* |
||||
* SPDX-License-Identifier: GPL-3.0 |
||||
* Aerocord, a vesktop fork for older microsoft NT releases such as NT 6.0, 6.1, 6.2 and 6.3.
|
||||
* Credits to vendicated and the rest of the vesktop contribuitors for making Vesktop! |
||||
*/ |
||||
|
||||
import { BrowserWindow } from "electron"; |
||||
import { join } from "path"; |
||||
import { SplashProps } from "shared/browserWinProperties"; |
||||
import { ICON_PATH, VIEW_DIR } from "shared/paths"; |
||||
|
||||
import { Settings } from "./settings"; |
||||
|
||||
export function createSplashWindow(startMinimized = false) { |
||||
const splash = new BrowserWindow({ |
||||
...SplashProps, |
||||
icon: ICON_PATH, |
||||
show: !startMinimized |
||||
}); |
||||
|
||||
splash.loadFile(join(VIEW_DIR, "splash.html")); |
||||
|
||||
const { splashBackground, splashColor, splashTheming } = Settings.store; |
||||
|
||||
if (splashTheming) { |
||||
if (splashColor) { |
||||
const semiTransparentSplashColor = splashColor.replace("rgb(", "rgba(").replace(")", ", 0.2)"); |
||||
|
||||
splash.webContents.insertCSS(`body { --fg: ${splashColor} !important }`); |
||||
splash.webContents.insertCSS(`body { --fg-semi-trans: ${semiTransparentSplashColor} !important }`); |
||||
} |
||||
|
||||
if (splashBackground) { |
||||
splash.webContents.insertCSS(`body { --bg: ${splashBackground} !important }`); |
||||
} |
||||
} |
||||
|
||||
return splash; |
||||
} |
@ -0,0 +1,118 @@ |
||||
/* |
||||
* SPDX-License-Identifier: GPL-3.0 |
||||
* Aerocord, a vesktop fork for older microsoft NT releases such as NT 6.0, 6.1, 6.2 and 6.3.
|
||||
* Credits to vendicated and the rest of the vesktop contribuitors for making Vesktop! |
||||
*/ |
||||
|
||||
import type { PatchBay as PatchBayType } from "@vencord/venmic"; |
||||
import { app, ipcMain } from "electron"; |
||||
import { join } from "path"; |
||||
import { IpcEvents } from "shared/IpcEvents"; |
||||
import { STATIC_DIR } from "shared/paths"; |
||||
|
||||
type LinkData = Parameters<PatchBayType["link"]>[0]; |
||||
|
||||
let PatchBay: typeof PatchBayType | undefined; |
||||
let patchBayInstance: PatchBayType | undefined; |
||||
|
||||
let imported = false; |
||||
let initialized = false; |
||||
|
||||
let hasPipewirePulse = false; |
||||
let isGlibCxxOutdated = false; |
||||
|
||||
function importVenmic() { |
||||
if (imported) { |
||||
return; |
||||
} |
||||
|
||||
imported = true; |
||||
|
||||
try { |
||||
PatchBay = (require(join(STATIC_DIR, `dist/venmic-${process.arch}.node`)) as typeof import("@vencord/venmic")) |
||||
.PatchBay; |
||||
|
||||
hasPipewirePulse = PatchBay.hasPipeWire(); |
||||
} catch (e: any) { |
||||
console.error("Failed to import venmic", e); |
||||
isGlibCxxOutdated = (e?.stack || e?.message || "").toLowerCase().includes("glibc"); |
||||
} |
||||
} |
||||
|
||||
function obtainVenmic() { |
||||
if (!imported) { |
||||
importVenmic(); |
||||
} |
||||
|
||||
if (PatchBay && !initialized) { |
||||
initialized = true; |
||||
|
||||
try { |
||||
patchBayInstance = new PatchBay(); |
||||
} catch (e: any) { |
||||
console.error("Failed to instantiate venmic", e); |
||||
} |
||||
} |
||||
|
||||
return patchBayInstance; |
||||
} |
||||
|
||||
function getRendererAudioServicePid() { |
||||
return ( |
||||
app |
||||
.getAppMetrics() |
||||
.find(proc => proc.name === "Audio Service") |
||||
?.pid?.toString() ?? "owo" |
||||
); |
||||
} |
||||
|
||||
ipcMain.handle(IpcEvents.VIRT_MIC_LIST, () => { |
||||
const audioPid = getRendererAudioServicePid(); |
||||
|
||||
const list = obtainVenmic() |
||||
?.list() |
||||
.filter(s => s["application.process.id"] !== audioPid) |
||||
.map(s => s["application.name"]); |
||||
|
||||
const uniqueTargets = [...new Set(list)]; |
||||
|
||||
return list ? { ok: true, targets: uniqueTargets, hasPipewirePulse } : { ok: false, isGlibCxxOutdated }; |
||||
}); |
||||
|
||||
ipcMain.handle(IpcEvents.VIRT_MIC_START, (_, targets: string[], workaround?: boolean) => { |
||||
const pid = getRendererAudioServicePid(); |
||||
|
||||
const data: LinkData = { |
||||
include: targets.map(target => ({ key: "application.name", value: target })), |
||||
exclude: [{ key: "application.process.id", value: pid }] |
||||
}; |
||||
|
||||
if (workaround) { |
||||
data.workaround = [ |
||||
{ key: "application.process.id", value: pid }, |
||||
{ key: "media.name", value: "RecordStream" } |
||||
]; |
||||
} |
||||
|
||||
return obtainVenmic()?.link(data); |
||||
}); |
||||
|
||||
ipcMain.handle(IpcEvents.VIRT_MIC_START_SYSTEM, (_, workaround?: boolean, onlyDefaultSpeakers?: boolean) => { |
||||
const pid = getRendererAudioServicePid(); |
||||
|
||||
const data: LinkData = { |
||||
exclude: [{ key: "application.process.id", value: pid }], |
||||
only_default_speakers: onlyDefaultSpeakers |
||||
}; |
||||
|
||||
if (workaround) { |
||||
data.workaround = [ |
||||
{ key: "application.process.id", value: pid }, |
||||
{ key: "media.name", value: "RecordStream" } |
||||
]; |
||||
} |
||||
|
||||
return obtainVenmic()?.link(data); |
||||
}); |
||||
|
||||
ipcMain.handle(IpcEvents.VIRT_MIC_STOP, () => obtainVenmic()?.unlink()); |
Loading…
Reference in new issue