Add voice audio, capture and transcript, browser monitor, and DM UI

This commit is contained in:
Fisto
2026-09-14 11:19:06 +02:00
parent 65f0788502
commit c003d9532f
27 changed files with 4479 additions and 239 deletions
+54 -1
View File
@@ -25,8 +25,11 @@ export type CoreEventListener = (event: any) => void;
interface Pending {
resolve: (value: any) => void;
reject: (error: Error) => void;
timer: ReturnType<typeof setTimeout>;
}
const REQUEST_TIMEOUT_MS = Number(process.env.VESKSLOP_REQUEST_TIMEOUT_MS ?? 30000);
export class CoreClient {
private nextId = 1;
private readonly pending = new Map<number, Pending>();
@@ -50,6 +53,7 @@ export class CoreClient {
socket.on("close", () => {
for (const request of this.pending.values()) {
clearTimeout(request.timer);
request.reject(new CoreError("DISCONNECTED", "core disconnected"));
}
this.pending.clear();
@@ -93,6 +97,7 @@ export class CoreClient {
const request = this.pending.get(message.id);
if (!request) return;
this.pending.delete(message.id);
clearTimeout(request.timer);
if (message.ok) request.resolve(message.result);
else request.reject(new CoreError(message.error?.code ?? "UNKNOWN", message.error?.message ?? "core error"));
@@ -102,7 +107,24 @@ export class CoreClient {
const id = this.nextId++;
return new Promise<T>((resolve, reject) => {
this.pending.set(id, { resolve, reject });
const timer = setTimeout(() => {
if (this.pending.delete(id)) {
reject(new CoreError("TIMEOUT", `the core did not answer ${action}`));
}
}, REQUEST_TIMEOUT_MS);
this.pending.set(id, {
resolve: value => {
clearTimeout(timer);
resolve(value);
},
reject: error => {
clearTimeout(timer);
reject(error);
},
timer
});
this.socket.write(JSON.stringify({ id, action, params }) + "\n");
});
}
@@ -158,6 +180,37 @@ export class CoreClient {
return this.request("voice.overview", { guildId });
}
async voiceJoin(channelId: string, mute = true) {
return this.request("voice.join", { channelId, mute });
}
async voiceLeave() {
return this.request("voice.leave");
}
async voiceMove(channelId: string) {
return this.request("voice.move", { channelId });
}
async voiceUsers(userIds: string[]) {
return this.request("voice.users", { userIds });
}
async userStatus(userIds: string[]) {
return this.request("user.status", { userIds });
}
async voiceDevices() {
return this.request("voice.devices");
}
async voiceSetDevices(inputDeviceId?: string, outputDeviceId?: string) {
return this.request("voice.setDevices", {
...(inputDeviceId ? { inputDeviceId } : {}),
...(outputDeviceId ? { outputDeviceId } : {})
});
}
async userSearch(query: string, guildId?: string, limit?: number) {
return this.request("user.search", {
query,