Update name, remove css building, remove cache size setting

This commit is contained in:
TheGreenPig 2024-09-18 01:47:49 +02:00
parent fce53b9535
commit 6c2222e295
4 changed files with 48 additions and 106 deletions

View file

@ -407,36 +407,6 @@ export function PencilIcon(props: IconProps) {
);
}
export function PreviewVisible(props: IconProps) {
return (
<Icon
{...props}
className={classes(props.className, "vc-preview-visible")}
viewBox="0 0 226 226"
>
<path
fill="currentColor"
d="M113,37.66667c-75.33333,0 -103.58333,75.33333 -103.58333,75.33333c0,0 28.25,75.33333 103.58333,75.33333c75.33333,0 103.58333,-75.33333 103.58333,-75.33333c0,0 -28.25,-75.33333 -103.58333,-75.33333zM113,65.91667c25.99942,0 47.08333,21.08392 47.08333,47.08333c0,25.99942 -21.08392,47.08333 -47.08333,47.08333c-25.99942,0 -47.08333,-21.08392 -47.08333,-47.08333c0,-25.99942 21.08392,-47.08333 47.08333,-47.08333zM113,84.75c-15.60204,0 -28.25,12.64796 -28.25,28.25c0,15.60204 12.64796,28.25 28.25,28.25c15.60204,0 28.25,-12.64796 28.25,-28.25c0,-15.60204 -12.64796,-28.25 -28.25,-28.25z"
/>
</Icon>
);
}
export function PreviewInvisible(props: IconProps) {
return (
<Icon
{...props}
className={classes(props.className, "vc-preview-invisible")}
viewBox="0 0 226 226"
>
<path
fill="currentColor"
d="M37.57471,28.15804c-3.83186,0.00101 -7.28105,2.32361 -8.72295,5.87384c-1.4419,3.55022 -0.58897,7.62011 2.15703,10.29267l16.79183,16.79183c-18.19175,14.60996 -29.9888,32.52303 -35.82747,43.03711c-3.12633,5.63117 -3.02363,12.41043 0.03678,18.07927c10.87625,20.13283 42.14532,66.10058 100.99007,66.10058c19.54493,0 35.83986,-5.13463 49.36394,-12.65365l19.31152,19.31152c2.36186,2.46002 5.8691,3.45098 9.16909,2.5907c3.3,-0.86028 5.87708,-3.43736 6.73736,-6.73736c0.86028,-3.3 -0.13068,-6.80724 -2.5907,-9.16909l-150.66666,-150.66667c-1.77289,-1.82243 -4.20732,-2.8506 -6.74984,-2.85075zM113,37.66667c-11.413,0 -21.60375,1.88068 -30.91683,4.81869l24.11182,24.11182c2.23175,-0.32958 4.47909,-0.6805 6.80501,-0.6805c25.99942,0 47.08333,21.08392 47.08333,47.08333c0,2.32592 -0.35092,4.57326 -0.6805,6.80501l32.29623,32.29623c10.1135,-11.22467 17.51573,-22.61015 21.94157,-30.18115c3.3335,-5.68767 3.32011,-12.67425 0.16553,-18.4655c-11.00808,-20.27408 -42.2439,-65.78792 -100.80615,-65.78792zM73.77002,87.08577l13.77555,13.77556c-1.77707,3.67147 -2.79557,7.77466 -2.79557,12.13867c0,15.60342 12.64658,28.25 28.25,28.25c4.364,0 8.46719,-1.01851 12.13867,-2.79557l13.79395,13.79395c-9.356,6.20362 -21.03043,9.17606 -33.4733,7.24642c-19.75617,-3.06983 -35.88427,-19.19794 -38.9541,-38.9541c-1.92879,-12.43739 1.0665,-24.10096 7.26481,-33.45491z"
/>
</Icon>
);
}
const WebsiteIconDark = "/assets/e1e96d89e192de1997f73730db26e94f.svg";
const WebsiteIconLight = "/assets/730f58bcfd5a57a5e22460c445a0c6cf.svg";
const GithubIconLight = "/assets/3ff98ad75ac94fa883af5ed62d17c459.svg";

View file

@ -4,15 +4,13 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { Logger } from "@utils/Logger";
export class LRUCache {
private cache: Map<string, string>;
private maxSize: number;
constructor() {
constructor(maxSize: number) {
this.cache = new Map();
this.maxSize = 50;
this.maxSize = maxSize;
}
get(key: string): string | undefined {
@ -47,16 +45,4 @@ export class LRUCache {
}
this.cache.clear();
}
setMaxSize(maxSize: number) {
if (maxSize < 1) {
new Logger("FileViewer").error("Cache size must be at least 1");
return;
}
this.maxSize = maxSize;
}
getMaxSize() {
return this.maxSize;
}
}

View file

@ -4,22 +4,20 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import "./fileViewer.css";
import "./pdfViewer.css";
import { get, set } from "@api/DataStore";
import { addAccessory, removeAccessory } from "@api/MessageAccessories";
import { updateMessage } from "@api/MessageUpdater";
import { definePluginSettings } from "@api/Settings";
import ErrorBoundary from "@components/ErrorBoundary";
import { PreviewInvisible, PreviewVisible } from "@components/Icons";
import { Devs } from "@utils/constants";
import { Logger } from "@utils/Logger";
import definePlugin, { OptionType, PluginNative } from "@utils/types";
import { Tooltip, useEffect, useState } from "@webpack/common";
import { Icons, Spinner, Tooltip, useEffect, useState } from "@webpack/common";
import { LRUCache } from "./cache";
const Native = VencordNative.pluginHelpers.FileViewer as PluginNative<typeof import("./native")>;
const Native = VencordNative.pluginHelpers.PdfViewer as PluginNative<typeof import("./native")>;
const settings = definePluginSettings({
autoEmptyCache: {
@ -32,20 +30,10 @@ const settings = definePluginSettings({
description: "Persist the state of opened/closed File Previews across channel switches and reloads.",
default: false
},
cacheSize: {
type: OptionType.SLIDER,
description: "Maximum number of PDF files to cache (after that, the least recently used file will be removed). Lower this value if you're running out of memory.",
default: 50,
restartNeeded: true,
markers: [10, 20, 30, 40, 50, 75, 100],
stickToMarkers: true,
}
});
const objectUrlsCache = new LRUCache();
const STORE_KEY = "FileViewer_PersistVisible";
let style: HTMLStyleElement;
const objectUrlsCache = new LRUCache(20);
const STORE_KEY = "PdfViewer_PersistVisible";
interface Attachment {
id: string;
@ -58,25 +46,19 @@ interface Attachment {
title: string;
spoiler: boolean;
previewBlobUrl?: string;
previewVisible?: boolean;
}
const stripLink = (url: string) => url.replace("https://cdn.discordapp.com/attachments/", "").split("/").slice(0, 2).join("-");
function FilePreview({ attachment }: { attachment: Attachment; }) {
const { previewBlobUrl } = attachment;
const { previewBlobUrl, previewVisible } = attachment;
if (!previewBlobUrl) return null;
if (!previewVisible) return null;
return <div className={"file-viewer container"} id={`file-viewer-${stripLink(attachment.url)}`}><embed src={previewBlobUrl} className="file-viewer preview" title={attachment.filename} /></div>;
}
async function buildCss() {
const visiblePreviews: Set<string> | undefined = await get(STORE_KEY);
const elements = [...(visiblePreviews || [])].map(url => `#file-viewer-${stripLink(url)}`).join(",");
style.textContent = `
:is(${elements}) {
display: flex !important;
}
`;
return (
<div className={"vc-pdf-viewer-container"}>
{previewBlobUrl ? <embed src={previewBlobUrl} className="vc-pdf-viewer-preview" title={attachment.filename} /> : <Spinner />}
</div>
);
}
function PreviewButton({ attachment, channelId, messageId }: { attachment: Attachment; channelId: string; messageId: string; }) {
@ -92,6 +74,7 @@ function PreviewButton({ attachment, channelId, messageId }: { attachment: Attac
try {
const buffer = await Native.getBufferResponse(attachment.url);
const file = new File([buffer], attachment.filename, { type: attachment.content_type });
const blobUrl = URL.createObjectURL(file);
objectUrlsCache.set(attachment.url, blobUrl);
setUrl(blobUrl);
@ -100,24 +83,31 @@ function PreviewButton({ attachment, channelId, messageId }: { attachment: Attac
}
};
const updateVisibility = async () => {
const data: Set<string> = await get(STORE_KEY) ?? new Set();
if (visible === null) {
setVisible(settings.store.persistPreviewState ? data.has(attachment.url) : false);
} else {
if (visible) data.add(attachment.url);
else data.delete(attachment.url);
await set(STORE_KEY, data);
attachment.previewVisible = visible;
updateMessage(channelId, messageId);
}
};
useEffect(() => {
get(STORE_KEY).then(async data => {
if (visible === null) {
setVisible(settings.store.persistPreviewState ? (data ?? new Set()).has(attachment.url) : false);
} else {
const persistSet = (data ?? new Set());
if (visible) persistSet.add(attachment.url);
else persistSet.delete(attachment.url);
await set(STORE_KEY, persistSet);
buildCss();
}
});
updateVisibility();
if (visible && !url) initPdfData();
}, [visible]);
useEffect(() => {
attachment.previewBlobUrl = url;
updateMessage(channelId, messageId,);
updateMessage(channelId, messageId);
return () => {
if (url && settings.store.autoEmptyCache) {
objectUrlsCache.delete(attachment.url);
@ -129,20 +119,20 @@ function PreviewButton({ attachment, channelId, messageId }: { attachment: Attac
{tooltipProps => (
<div
{...tooltipProps}
className="file-viewer toggle"
className="vc-pdf-viewer-toggle"
role="button"
onClick={() => {
setVisible(v => !v);
}}
>
{visible ? <PreviewInvisible /> : <PreviewVisible />}
{visible ? <Icons.EyeSlashIcon /> : <Icons.EyeIcon />}
</div>
)}
</Tooltip>;
}
export default definePlugin({
name: "FileViewer",
name: "PdfViewer",
description: "Preview PDF Files without having to download them",
authors: [Devs.AGreenPig],
dependencies: ["MessageAccessoriesAPI", "MessageUpdaterAPI",],
@ -157,8 +147,7 @@ export default definePlugin({
}
],
start() {
objectUrlsCache.setMaxSize(Math.round(settings.store.cacheSize));
addAccessory("fileViewer", props => {
addAccessory("pdfViewer", props => {
const pdfAttachments = props.message.attachments.filter(a => a.content_type === "application/pdf");
if (!pdfAttachments.length) return null;
@ -170,18 +159,13 @@ export default definePlugin({
</ErrorBoundary>
);
}, -1);
style = document.createElement("style");
style.id = "VencordFileViewer";
document.head.appendChild(style);
},
renderPreviewButton: ErrorBoundary.wrap(e => {
if (e.item.originalItem.content_type !== "application/pdf") return null;
return <PreviewButton attachment={e.item.originalItem} channelId={e.message.channel_id} messageId={e.message.id} />;
},
}),
stop() {
objectUrlsCache.clear();
removeAccessory("fileViewer");
style.remove();
removeAccessory("pdfViewer");
}
});

View file

@ -1,4 +1,4 @@
.file-viewer.container {
.vc-pdf-viewer-container {
resize: both;
overflow: hidden;
max-width: 100%;
@ -6,16 +6,18 @@
max-height: 80vh;
min-height: 500px;
box-sizing: border-box;
display: none; /* Will be set with buildCss */
display: flex;
justify-content: center;
align-items: center;
}
.file-viewer.preview {
.vc-pdf-viewer-preview {
width: 100%;
flex-grow: 1;
border: none;
}
.file-viewer.toggle {
.vc-pdf-viewer-toggle {
justify-self: center;
display: flex;
justify-content: center;
@ -24,6 +26,6 @@
cursor: pointer;
}
.file-viewer.toggle:hover {
.vc-pdf-viewer-toggle:hover {
color: var(--interactive-hover);
}