Plugin

CallTimer

Adds a timer to vcs

Voice Utility
index.tsx
Download

Source

src/plugins/callTimer/index.tsx
1/*
2 * FiveCord — a Discord client mod
3 * Copyright (c) 2025 FiveCord
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
7import { definePluginSettings } from "@api/Settings";
8import ErrorBoundary from "@components/ErrorBoundary";
9import { Devs } from "@utils/constants";
10import { useTimer } from "@utils/react";
11import definePlugin, { OptionType } from "@utils/types";
12import { React } from "@webpack/common";
13
14import alignedChatInputFix from "./alignedChatInputFix.css?managed";
15
16const settings = definePluginSettings({
17 format: {
18 type: OptionType.SELECT,
19 description: "The timer format. This can be any valid moment.js format",
20 options: [
21 {
22 label: "30d 23:00:42",
23 value: "stopwatch",
24 default: true
25 },
26 {
27 label: "30d 23h 00m 42s",
28 value: "human"
29 }
30 ]
31 }
32});
33
34function formatDuration(ms: number) {
35 // here be dragons (moment fucking sucks)
36 const human = settings.store.format === "human";
37
38 const format = (n: number) => human ? n : n.toString().padStart(2, "0");
39 const unit = (s: string) => human ? s : "";
40 const delim = human ? " " : ":";
41
42 // thx copilot
43 const d = Math.floor(ms / 86400000);
44 const h = Math.floor((ms % 86400000) / 3600000);
45 const m = Math.floor(((ms % 86400000) % 3600000) / 60000);
46 const s = Math.floor((((ms % 86400000) % 3600000) % 60000) / 1000);
47
48 let res = "";
49 if (d) res += `${d}d `;
50 if (h || res) res += `${format(h)}${unit("h")}${delim}`;
51 if (m || res || !human) res += `${format(m)}${unit("m")}${delim}`;
52 res += `${format(s)}${unit("s")}`;
53
54 return res;
55}
56
57
58
59export default definePlugin({
60 name: "CallTimer",
61 description: "Adds a timer to vcs",
62 tags: ["Voice", "Utility"],
63 authors: [Devs.Ven],
64 managedStyle: alignedChatInputFix,
65 settings,
66
67 startTime: 0,
68 interval: void 0 as NodeJS.Timeout | undefined,
69
70 patches: [
71 {
72 find: '"RTCConnectionMenu"',
73 replacement: {
74 match: /("RTCConnectionMenu".{0,200}?lineClamp:1,children:)(\i)(?=,|}\))/,
75 replace: "$1[$2,$self.renderTimer({ channelId: this?.props?.channel?.id })]"
76 }
77 },
78 ],
79
80 renderTimer: ErrorBoundary.wrap(({ channelId }: { channelId: string; }) => {
81 const time = useTimer({ deps: [channelId] });
82
83 return (
84 <p style={{ margin: 0, fontFamily: "var(--font-code)" }}>
85 {formatDuration(time)}
86 </p>
87 );
88 }, { noop: true }),
89});
90