Skip to content

Commit a040c8d

Browse files
committed
SpotifyControls: improve time formatting for tracks over an hour
1 parent 0f10b57 commit a040c8d

4 files changed

Lines changed: 41 additions & 40 deletions

File tree

src/plugins/callTimer/index.tsx

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { definePluginSettings } from "@api/Settings";
2020
import ErrorBoundary from "@components/ErrorBoundary";
2121
import { Devs } from "@utils/constants";
2222
import { useTimer } from "@utils/react";
23+
import { formatDuration } from "@utils/text";
2324
import definePlugin, { OptionType } from "@utils/types";
2425
import { React } from "@webpack/common";
2526

@@ -39,33 +40,10 @@ const settings = definePluginSettings({
3940
label: "30d 23h 00m 42s",
4041
value: "human"
4142
}
42-
]
43+
] as const
4344
}
4445
});
4546

46-
function formatDuration(ms: number) {
47-
// here be dragons (moment fucking sucks)
48-
const human = settings.store.format === "human";
49-
50-
const format = (n: number) => human ? n : n.toString().padStart(2, "0");
51-
const unit = (s: string) => human ? s : "";
52-
const delim = human ? " " : ":";
53-
54-
// thx copilot
55-
const d = Math.floor(ms / 86400000);
56-
const h = Math.floor((ms % 86400000) / 3600000);
57-
const m = Math.floor(((ms % 86400000) % 3600000) / 60000);
58-
const s = Math.floor((((ms % 86400000) % 3600000) % 60000) / 1000);
59-
60-
let res = "";
61-
if (d) res += `${d}d `;
62-
if (h || res) res += `${format(h)}${unit("h")}${delim}`;
63-
if (m || res || !human) res += `${format(m)}${unit("m")}${delim}`;
64-
res += `${format(s)}${unit("s")}`;
65-
66-
return res;
67-
}
68-
6947

7048

7149
export default definePlugin({
@@ -94,7 +72,7 @@ export default definePlugin({
9472

9573
return (
9674
<p style={{ margin: 0, fontFamily: "var(--font-code)" }}>
97-
{formatDuration(time)}
75+
{formatDuration(time, settings.store.format === "human")}
9876
</p>
9977
);
10078
}, { noop: true }),

src/plugins/showHiddenChannels/components/HiddenChannelLockScreen.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import PermissionsViewerPlugin from "@plugins/permissionsViewer";
2222
import openRolesAndUsersPermissionsModal from "@plugins/permissionsViewer/components/RolesAndUsersPermissions";
2323
import { sortPermissionOverwrites } from "@plugins/permissionsViewer/utils";
2424
import { classes } from "@utils/misc";
25-
import { formatDuration } from "@utils/text";
25+
import { formatDurationVerbose } from "@utils/text";
2626
import type { Channel, RoleOrUserPermission } from "@vencord/discord-types";
2727
import { findByPropsLazy, findComponentByCodeLazy, findCssClassesLazy } from "@webpack";
2828
import { EmojiStore, FluxDispatcher, GuildMemberStore, GuildStore, Parser, PermissionsBits, PermissionStore, SnowflakeUtils, Text, Timestamp, Tooltip, useEffect, useState } from "@webpack/common";
@@ -204,11 +204,11 @@ function HiddenChannelLockScreen({ channel }: { channel: Channel; }) {
204204
<Text variant="text-md/normal">Last message pin: <Timestamp timestamp={new Date(lastPinTimestamp)} /></Text>
205205
}
206206
{(rateLimitPerUser ?? 0) > 0 &&
207-
<Text variant="text-md/normal">Slowmode: {formatDuration(rateLimitPerUser!, "seconds")}</Text>
207+
<Text variant="text-md/normal">Slowmode: {formatDurationVerbose(rateLimitPerUser!, "seconds")}</Text>
208208
}
209209
{(defaultThreadRateLimitPerUser ?? 0) > 0 &&
210210
<Text variant="text-md/normal">
211-
Default thread slowmode: {formatDuration(defaultThreadRateLimitPerUser!, "seconds")}
211+
Default thread slowmode: {formatDurationVerbose(defaultThreadRateLimitPerUser!, "seconds")}
212212
</Text>
213213
}
214214
{((channel.isGuildVoice() || channel.isGuildStageVoice()) && bitrate != null) &&
@@ -223,7 +223,7 @@ function HiddenChannelLockScreen({ channel }: { channel: Channel; }) {
223223
{(defaultAutoArchiveDuration ?? 0) > 0 &&
224224
<Text variant="text-md/normal">
225225
Default inactivity duration before archiving {channel.isForumChannel() ? "posts" : "threads"}:
226-
{" " + formatDuration(defaultAutoArchiveDuration!, "minutes")}
226+
{" " + formatDurationVerbose(defaultAutoArchiveDuration!, "minutes")}
227227
</Text>
228228
}
229229
{defaultForumLayout != null &&

src/plugins/spotifyControls/PlayerComponent.tsx

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { debounce } from "@shared/debounce";
2626
import { classNameFactory } from "@utils/css";
2727
import { copyWithToast, openImageModal } from "@utils/discord";
2828
import { classes } from "@utils/misc";
29+
import { formatDuration } from "@utils/text";
2930
import { ContextMenuApi, FluxDispatcher, Menu, React, useEffect, useState, useStateFromStores } from "@webpack/common";
3031

3132
import { settings } from ".";
@@ -34,13 +35,6 @@ import { SpotifyStore, Track } from "./SpotifyStore";
3435

3536
const cl = classNameFactory("vc-spotify-");
3637

37-
function msToHuman(ms: number) {
38-
const minutes = ms / 1000 / 60;
39-
const m = Math.floor(minutes);
40-
const s = Math.floor((minutes - m) * 60);
41-
return `${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
42-
}
43-
4438
function Svg(path: string, label: string) {
4539
return () => (
4640
<svg
@@ -193,23 +187,23 @@ function SpotifySeekBar() {
193187
className={cl("progress-time") + " " + cl("time-left")}
194188
aria-label="Progress"
195189
>
196-
{msToHuman(position)}
190+
{formatDuration(position)}
197191
</Span>
198192
<SeekBar
199193
initialValue={position}
200194
minValue={0}
201195
maxValue={duration}
202196
onValueChange={onChange}
203197
asValueChanges={onChange}
204-
onValueRender={msToHuman}
198+
onValueRender={formatDuration}
205199
/>
206200
<Span
207201
size="xs"
208202
weight="medium"
209203
className={cl("progress-time") + " " + cl("time-right")}
210204
aria-label="Total Duration"
211205
>
212-
{msToHuman(duration)}
206+
{formatDuration(duration)}
213207
</Span>
214208
</div>
215209
);

src/utils/text.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
* along with this program. If not, see <https://www.gnu.org/licenses/>.
1717
*/
1818

19+
import { isTruthy } from "./guards";
20+
1921
// Utils for readable text transformations eg: `toTitle(fromKebab())`
2022

2123
// Case style to words
@@ -51,7 +53,7 @@ function getUnitStr(unit: Units, isOne: boolean, short: boolean) {
5153
* @param unit The unit the time is on
5254
* @param short Whether to use short units like "d" instead of "days"
5355
*/
54-
export function formatDuration(time: number, unit: Units, short: boolean = false) {
56+
export function formatDurationVerbose(time: number, unit: Units, short: boolean = false) {
5557
const { moment } = require("@webpack/common") as typeof import("@webpack/common");
5658
const dur = moment.duration(time, unit);
5759

@@ -93,6 +95,33 @@ export function formatDuration(time: number, unit: Units, short: boolean = false
9395
return res.length ? res : `0 ${getUnitStr(unit, false, short)}`;
9496
}
9597

98+
export function formatDuration(ms: number, human = false) {
99+
const DAY = 86_400_000;
100+
const HOUR = 3_600_000;
101+
const MINUTE = 60_000;
102+
103+
const days = Math.floor(ms / DAY);
104+
const hours = Math.floor((ms % DAY) / HOUR);
105+
const minutes = Math.floor((ms % HOUR) / MINUTE);
106+
const seconds = Math.floor((ms % MINUTE) / 1000);
107+
108+
const pad = (n: number) => human ? n : n.toString().padStart(2, "0");
109+
const unit = (s: string) => human ? s : "";
110+
111+
const showDays = days !== 0;
112+
const showHours = showDays || hours !== 0;
113+
const showMinutes = showHours || minutes !== 0 || !human;
114+
115+
const duration = [
116+
showHours && `${pad(hours)}${unit("h")}`,
117+
showMinutes && `${pad(minutes)}${unit("m")}`,
118+
`${pad(seconds)}${unit("s")}`
119+
].filter(isTruthy).join(human ? " " : ":");
120+
121+
const prefix = showDays ? `${days}d ` : "";
122+
return prefix + duration;
123+
}
124+
96125
/**
97126
* Join an array of strings in a human readable way (1, 2 and 3)
98127
* @param elements Elements

0 commit comments

Comments
 (0)