2026-05-13 15:56:42 +07:00
|
|
|
import path from "node:path";
|
|
|
|
|
import type { Client, VoiceChannel } from "discord.js-selfbot-v13";
|
2026-05-13 16:05:19 +07:00
|
|
|
import { config } from "../config";
|
2026-05-13 15:56:42 +07:00
|
|
|
import type { SegmentMetadata, SegmentState, UserMetadata } from "../types";
|
|
|
|
|
|
|
|
|
|
export async function collectUserMetadata(
|
|
|
|
|
client: Client,
|
|
|
|
|
userId: string,
|
|
|
|
|
channel: VoiceChannel,
|
|
|
|
|
): Promise<UserMetadata> {
|
|
|
|
|
const user =
|
|
|
|
|
client.users.cache.get(userId) ||
|
|
|
|
|
(await client.users.fetch(userId).catch(() => null));
|
|
|
|
|
const member =
|
|
|
|
|
channel.guild.members.cache.get(userId) ||
|
|
|
|
|
(await channel.guild.members.fetch(userId).catch(() => null));
|
|
|
|
|
const username = user?.username ?? "Unknown User";
|
|
|
|
|
const roles =
|
|
|
|
|
member?.roles.cache
|
|
|
|
|
.filter((role) => role.id !== channel.guild.id)
|
|
|
|
|
.sort((a, b) => b.position - a.position)
|
2026-05-13 15:56:56 +07:00
|
|
|
.map((role) => ({
|
|
|
|
|
id: role.id,
|
|
|
|
|
name: role.name,
|
|
|
|
|
position: role.position,
|
|
|
|
|
})) ?? [];
|
2026-05-13 15:56:42 +07:00
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
userId,
|
|
|
|
|
username,
|
|
|
|
|
tag: user?.tag ?? "Unknown#0000",
|
|
|
|
|
displayName: member?.displayName ?? username,
|
|
|
|
|
avatarUrl:
|
2026-05-13 16:05:19 +07:00
|
|
|
user?.displayAvatarURL({
|
|
|
|
|
format: "png",
|
2026-05-13 16:57:07 +07:00
|
|
|
size: config.AVATAR_SIZE as
|
2026-05-13 16:05:19 +07:00
|
|
|
| 16
|
|
|
|
|
| 32
|
|
|
|
|
| 64
|
|
|
|
|
| 128
|
|
|
|
|
| 256
|
|
|
|
|
| 512
|
|
|
|
|
| 1024
|
|
|
|
|
| 2048
|
|
|
|
|
| 4096,
|
|
|
|
|
}) ?? "https://cdn.discordapp.com/embed/avatars/0.png",
|
2026-05-13 15:56:42 +07:00
|
|
|
bot: user?.bot ?? false,
|
|
|
|
|
roles,
|
|
|
|
|
highestRole: roles[0] ?? null,
|
|
|
|
|
joinedTimestamp: member?.joinedTimestamp ?? null,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function createSegmentMetadata(
|
|
|
|
|
user: UserMetadata,
|
|
|
|
|
segment: SegmentState,
|
|
|
|
|
sessionId: string,
|
|
|
|
|
sessionStartTime: number,
|
|
|
|
|
recordingSegmentMs: number,
|
|
|
|
|
): SegmentMetadata {
|
|
|
|
|
const endTime = segment.endTime ?? Date.now();
|
|
|
|
|
return {
|
|
|
|
|
...user,
|
|
|
|
|
sessionId,
|
|
|
|
|
sessionStartTime,
|
|
|
|
|
segmentIndex: segment.index,
|
|
|
|
|
segmentMs: recordingSegmentMs,
|
|
|
|
|
startTime: segment.startTime,
|
|
|
|
|
endTime,
|
|
|
|
|
durationMs: endTime - segment.startTime,
|
|
|
|
|
filename: path.basename(segment.filename),
|
|
|
|
|
};
|
|
|
|
|
}
|