refactor: make hardcoded values configurable via env vars

This commit is contained in:
MythEclipse
2026-05-13 16:05:19 +07:00
parent 48cc83f624
commit 7a5ac2e34a
6 changed files with 64 additions and 10 deletions

View File

@@ -5,6 +5,15 @@ export interface AppConfig {
recordingSegmentMs: number;
decoderRotateMs: number;
decoderCooldownMs: number;
webserverPort: number;
voiceConnectionTimeoutMs: number;
reconnectTimeoutMs: number;
audioStreamSilenceDurationMs: number;
packetFilterMinSize: number;
opusFrameSize: number;
audioSampleRate: number;
audioChannels: number;
avatarSize: number;
}
export function parseBoolean(
@@ -30,7 +39,22 @@ export function loadConfig(env: NodeJS.ProcessEnv = process.env): AppConfig {
recordingsDir: env.RECORDINGS_DIR ?? "./recordings",
recordingSegmentMs: parsePositiveNumber(env.RECORDING_SEGMENT_MS, 5_000),
decoderRotateMs: parsePositiveNumber(env.DECODER_ROTATE_MS, 5_000),
decoderCooldownMs: 30_000,
decoderCooldownMs: parsePositiveNumber(env.DECODER_COOLDOWN_MS, 30_000),
webserverPort: parsePositiveNumber(env.WEBSERVER_PORT, 3000),
voiceConnectionTimeoutMs: parsePositiveNumber(
env.VOICE_CONNECTION_TIMEOUT_MS,
15_000,
),
reconnectTimeoutMs: parsePositiveNumber(env.RECONNECT_TIMEOUT_MS, 5_000),
audioStreamSilenceDurationMs: parsePositiveNumber(
env.AUDIO_STREAM_SILENCE_DURATION_MS,
3000,
),
packetFilterMinSize: parsePositiveNumber(env.PACKET_FILTER_MIN_SIZE, 8),
opusFrameSize: parsePositiveNumber(env.OPUS_FRAME_SIZE, 960),
audioSampleRate: parsePositiveNumber(env.AUDIO_SAMPLE_RATE, 48000),
audioChannels: parsePositiveNumber(env.AUDIO_CHANNELS, 2),
avatarSize: parsePositiveNumber(env.AVATAR_SIZE, 64),
};
}

View File

@@ -59,7 +59,7 @@ client.on("ready", async () => {
}
// Start Webserver
startWebserver(3000);
startWebserver(config.webserverPort);
});
client.on("error", (err) => {

View File

@@ -59,7 +59,11 @@ export async function startRecording(
// Tunggu sampai benar-benar terhubung
try {
await entersState(connection, VoiceConnectionStatus.Ready, 15_000);
await entersState(
connection,
VoiceConnectionStatus.Ready,
config.voiceConnectionTimeoutMs,
);
if (config.verbose) {
console.log("[recorder] Connected to voice channel. Recording started.");
}
@@ -97,7 +101,7 @@ export async function startRecording(
try {
// --- OGG file recording with segment rotation ---
const packetFilterForOgg = new PacketFilter(8);
const packetFilterForOgg = new PacketFilter(config.packetFilterMinSize);
const audioStream = receiver.subscribe(userId, {
end: {
behavior: EndBehaviorType.AfterSilence,
@@ -201,8 +205,16 @@ export async function startRecording(
}
try {
await Promise.race([
entersState(connection, VoiceConnectionStatus.Signalling, 5_000),
entersState(connection, VoiceConnectionStatus.Connecting, 5_000),
entersState(
connection,
VoiceConnectionStatus.Signalling,
config.reconnectTimeoutMs,
),
entersState(
connection,
VoiceConnectionStatus.Connecting,
config.reconnectTimeoutMs,
),
]);
// Berhasil reconnect
} catch {

View File

@@ -1,4 +1,5 @@
import { EndBehaviorType, type VoiceReceiver } from "@discordjs/voice";
import { config } from "../config";
export interface AudioStreamHandlers {
onPacket: (chunk: Buffer) => void;
@@ -14,7 +15,7 @@ export function subscribeToAudioStream(
const audioStream = receiver.subscribe(userId, {
end: {
behavior: EndBehaviorType.AfterSilence,
duration: 3000,
duration: config.audioStreamSilenceDurationMs,
},
});

View File

@@ -1,4 +1,5 @@
import prism from "prism-media";
import { config } from "../config";
export interface OpusDecoderOptions {
cooldownMs: number;
@@ -23,7 +24,11 @@ export class OpusDecoder {
this.createDecoderFn =
options.createDecoder ??
(() =>
new prism.opus.Decoder({ frameSize: 960, channels: 2, rate: 48000 }));
new prism.opus.Decoder({
frameSize: config.opusFrameSize,
channels: config.audioChannels as 1 | 2,
rate: config.audioSampleRate as 8000 | 12000 | 16000 | 24000 | 48000,
}));
}
rotateIfNeeded(): void {

View File

@@ -1,5 +1,6 @@
import path from "node:path";
import type { Client, VoiceChannel } from "discord.js-selfbot-v13";
import { config } from "../config";
import type { SegmentMetadata, SegmentState, UserMetadata } from "../types";
export async function collectUserMetadata(
@@ -30,8 +31,19 @@ export async function collectUserMetadata(
tag: user?.tag ?? "Unknown#0000",
displayName: member?.displayName ?? username,
avatarUrl:
user?.displayAvatarURL({ format: "png", size: 64 }) ??
"https://cdn.discordapp.com/embed/avatars/0.png",
user?.displayAvatarURL({
format: "png",
size: config.avatarSize as
| 16
| 32
| 64
| 128
| 256
| 512
| 1024
| 2048
| 4096,
}) ?? "https://cdn.discordapp.com/embed/avatars/0.png",
bot: user?.bot ?? false,
roles,
highestRole: roles[0] ?? null,