Plugin
ValidReply
Fixes "Message could not be loaded" upon hovering over the reply
1
/*2
* FiveCord — a Discord client mod3
* Copyright (c) 2025 FiveCord4
* SPDX-License-Identifier: GPL-3.0-or-later5
*/6
7
import { Devs } from "@utils/constants";8
import definePlugin from "@utils/types";9
import { Channel, Message, User } from "@vencord/discord-types";10
import { findByCodeLazy } from "@webpack";11
import { FluxDispatcher, RestAPI } from "@webpack/common";12
13
const enum ReferencedMessageState {14
Loaded,15
NotLoaded,16
Deleted17
}18
19
interface Reply {20
baseAuthor: User,21
baseMessage: Message;22
channel: Channel;23
referencedMessage: { state: ReferencedMessageState; };24
compact: boolean;25
isReplyAuthorBlocked: boolean;26
}27
28
const fetching = new Map<string, string>();29
let ReplyStore: any;30
31
const createMessageRecord = findByCodeLazy(".createFromServer(", ".isBlockedForMessage", "messageReference:");32
33
export default definePlugin({34
name: "ValidReply",35
description: 039;Fixes "Message could not be loaded" upon hovering over the reply039;,36
tags: ["Chat", "Utility"],37
authors: [Devs.FiveCord],38
patches: [39
{40
// Same find as in ReplyTimestamp41
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: messageId75
},76
retries: 277
})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.Deleted85
});86
87
FluxDispatcher.dispatch({88
type: "MESSAGE_DELETE",89
channelId: channelId,90
message: messageId91
});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: reply101
});102
}103
})104
.catch(() => { })105
.finally(() => {106
fetching.delete(messageId);107
});108
}109
});110