Plugin
FixImagesQuality
Improves quality of images by loading them at their original resolution
1
import { definePluginSettings } from "@api/Settings";2
import { Card } from "@components/Card";3
import { Flex } from "@components/Flex";4
import { Margins } from "@components/margins";5
import { Paragraph } from "@components/Paragraph";6
import { Devs } from "@utils/constants";7
import { Logger } from "@utils/Logger";8
import definePlugin, { OptionType } from "@utils/types";9
10
const settings = definePluginSettings({11
originalImagesInChat: {12
type: OptionType.BOOLEAN,13
description: "Also load the original image in Chat. WARNING: Read the caveats above",14
default: false,15
}16
});17
18
export default definePlugin({19
name: "FixImagesQuality",20
description: "Improves quality of images by loading them at their original resolution",21
tags: ["Media", "Appearance"],22
authors: [Devs.Nuckyz, Devs.Ven],23
settings,24
25
patches: [26
{27
find: ".handleImageLoad)",28
replacement: {29
match: /getSrc\(\i\)\{/,30
replace: "$&var _vcSrc=$self.getSrc(this?.props,arguments[1]);if(_vcSrc)return _vcSrc;"31
}32
}33
],34
35
settingsAboutComponent() {36
return (37
<Card variant="normal">38
<Flex flexDirection="column" gap="4px">39
<Paragraph size="md" weight="semibold">The default behaviour is the following:</Paragraph>40
<Paragraph>41
<ul>42
<li>— In chat, optimised but full resolution images will be loaded.</li>43
<li>— In the image modal, the original image will be loaded.</li>44
</ul>45
</Paragraph>46
<Paragraph size="md" weight="semibold" className={Margins.top8}>You can also enable original image in chat, but beware of the following caveats:</Paragraph>47
<Paragraph>48
<ul>49
<li>— Animated images (GIF, WebP, etc.) in chat will always animate, regardless of if the App is focused.</li>50
<li>— May cause lag.</li>51
</ul>52
</Paragraph>53
</Flex>54
</Card>55
);56
},57
58
getSrc(props: { src: string; width: number; height: number; contentType: string; mosaicStyleAlt?: boolean; trigger?: string; }, freeze?: boolean) {59
if (!props?.src) return;60
61
try {62
const { contentType, height, src, width, mosaicStyleAlt, trigger } = props;63
64
// Embed images do not have a content type set.65
// It's difficult to differentiate between images and videos. but mosaicStyleAlt seems exclusive to images66
const isImage = contentType?.startsWith("image/") ?? (typeof mosaicStyleAlt === "boolean");67
if (!isImage || src.startsWith("data:")) return;68
69
const url = new URL(src);70
if (!url.pathname.startsWith("/attachments/")) return;71
72
url.searchParams.set("animated", String(!freeze));73
if (freeze && url.pathname.endsWith(".gif")) {74
// gifs don't support animated=false, so we have no choice but to use webp75
url.searchParams.set("format", "webp");76
}77
78
const isModal = !!trigger;79
if (!settings.store.originalImagesInChat && !isModal) {80
// make sure the image is not too large81
const pixels = width * height;82
const limit = 2000 * 1200;83
84
if (pixels <= limit)85
return url.toString();86
87
const scale = Math.sqrt(pixels / limit);88
89
url.searchParams.set("width", Math.round(width / scale).toString());90
url.searchParams.set("height", Math.round(height / scale).toString());91
return url.toString();92
}93
94
url.hostname = "cdn.discordapp.com";95
return url.toString();96
} catch (e) {97
new Logger("FixImagesQuality").error("Failed to make image src", e);98
return;99
}100
}101
});102