Plugin

ValidReply

Fixes "Message could not be loaded" upon hovering over the reply

Chat Utility
index.ts
Download

Source

src/plugins/validReply/index.ts
1/*
2 * FiveCord — a Discord client mod
3 * Copyright (c) 2025 FiveCord
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
7import { Devs } from "@utils/constants";
8import definePlugin from "@utils/types";
9import { Channel, Message, User } from "@vencord/discord-types";
10import { findByCodeLazy } from "@webpack";
11import { FluxDispatcher, RestAPI } from "@webpack/common";
12
13const enum ReferencedMessageState {
14 Loaded,
15 NotLoaded,
16 Deleted
17}
18
19interface Reply {
20 baseAuthor: User,
21 baseMessage: Message;
22 channel: Channel;
23 referencedMessage: { state: ReferencedMessageState; };
24 compact: boolean;
25 isReplyAuthorBlocked: boolean;
26}
27
28const fetching = new Map<string, string>();
29let ReplyStore: any;
30
31const createMessageRecord = findByCodeLazy(".createFromServer(", ".isBlockedForMessage", "messageReference:");
32
33export default definePlugin({
34 name: "ValidReply",
35 description: &#039;Fixes "Message could not be loaded" upon hovering over the reply&#039;,
36 tags: ["Chat", "Utility"],
37 authors: [Devs.FiveCord],
38 patches: [
39 {
40 // Same find as in ReplyTimestamp
41 find: "#{intl::REPLY_QUOTE_MESSAGE_NOT_LOADED}",
42 replacement: {
43 match: /#{intl::REPLY_QUOTE_MESSAGE_NOT_LOADED}\)/,
44 replace: "$&,onMouseEnter:()=>$self.fetchReply(arguments[0])"
45 }
46 },
47 {
48 find: "ReferencedMessageStore",
49 replacement: [
50 {
51 match: /_channelCaches=new Map;/,
52 replace: "$&_=$self.setReplyStore(this);"
53 }
54 ]
55 }
56 ],
57
58 setReplyStore(store: any) {
59 ReplyStore = store;
60 },
61
62 async fetchReply(reply: Reply) {
63 const { channel_id: channelId, message_id: messageId } = reply.baseMessage.messageReference!;
64
65 if (fetching.has(messageId)) {
66 return;
67 }
68 fetching.set(messageId, channelId);
69
70 RestAPI.get({
71 url: `/channels/${channelId}/messages`,
72 query: {
73 limit: 1,
74 around: messageId
75 },
76 retries: 2
77 })
78 .then(res => {
79 const reply: Message | undefined = res?.body?.[0];
80 if (!reply) return;
81
82 if (reply.id !== messageId) {
83 ReplyStore.set(channelId, messageId, {
84 state: ReferencedMessageState.Deleted
85 });
86
87 FluxDispatcher.dispatch({
88 type: "MESSAGE_DELETE",
89 channelId: channelId,
90 message: messageId
91 });
92 } else {
93 ReplyStore.set(reply.channel_id, reply.id, {
94 state: ReferencedMessageState.Loaded,
95 message: createMessageRecord(reply)
96 });
97
98 FluxDispatcher.dispatch({
99 type: "MESSAGE_UPDATE",
100 message: reply
101 });
102 }
103 })
104 .catch(() => { })
105 .finally(() => {
106 fetching.delete(messageId);
107 });
108 }
109});
110