mirror of
https://github.com/ZeppelinBot/Zeppelin.git
synced 2025-07-07 19:17:19 +00:00
feat: update to djs 14.19.3, node 22, zod 4
This commit is contained in:
parent
595e1a0556
commit
09eb8e92f2
189 changed files with 1244 additions and 900 deletions
|
@ -0,0 +1,116 @@
|
|||
import { GuildBasedChannel, Message, OmitPartialGroupDMChannel, Snowflake, TextBasedChannel } from "discord.js";
|
||||
import { DAYS, getInviteCodesInString } from "../../../utils.js";
|
||||
import { GuildPluginData } from "knub";
|
||||
import { UtilityPluginType } from "../types.js";
|
||||
import { snowflakeToTimestamp } from "../../../utils/snowflakeToTimestamp.js";
|
||||
import { humanizeDurationShort } from "../../../humanizeDuration.js";
|
||||
import { allowTimeout } from "../../../RegExpRunner.js";
|
||||
import { SavedMessage } from "../../../data/entities/SavedMessage.js";
|
||||
|
||||
const MAX_CLEAN_COUNT = 300;
|
||||
const MAX_CLEAN_TIME = 1 * DAYS;
|
||||
const MAX_CLEAN_API_REQUESTS = 20;
|
||||
|
||||
export interface FetchChannelMessagesToCleanOpts {
|
||||
count: number;
|
||||
beforeId: string;
|
||||
upToId?: string;
|
||||
authorId?: string;
|
||||
includePins?: boolean;
|
||||
onlyBotMessages?: boolean;
|
||||
onlyWithInvites?: boolean;
|
||||
matchContent?: RegExp;
|
||||
}
|
||||
|
||||
export interface SuccessResult {
|
||||
messages: SavedMessage[];
|
||||
note: string;
|
||||
}
|
||||
|
||||
export interface ErrorResult {
|
||||
error: string;
|
||||
}
|
||||
|
||||
export type FetchChannelMessagesToCleanResult = SuccessResult | ErrorResult;
|
||||
|
||||
export async function fetchChannelMessagesToClean(pluginData: GuildPluginData<UtilityPluginType>, targetChannel: GuildBasedChannel & TextBasedChannel, opts: FetchChannelMessagesToCleanOpts): Promise<FetchChannelMessagesToCleanResult> {
|
||||
if (opts.count > MAX_CLEAN_COUNT || opts.count <= 0) {
|
||||
return { error: `Clean count must be between 1 and ${MAX_CLEAN_COUNT}` };
|
||||
}
|
||||
|
||||
const result: FetchChannelMessagesToCleanResult = {
|
||||
messages: [],
|
||||
note: "",
|
||||
};
|
||||
|
||||
const timestampCutoff = snowflakeToTimestamp(opts.beforeId) - MAX_CLEAN_TIME;
|
||||
let foundId = false;
|
||||
|
||||
let pinIds: Set<Snowflake> = new Set();
|
||||
if (!opts.includePins) {
|
||||
pinIds = new Set((await targetChannel.messages.fetchPinned()).keys());
|
||||
}
|
||||
|
||||
let rawMessagesToClean: Array<OmitPartialGroupDMChannel<Message<true>>> = [];
|
||||
let beforeId = opts.beforeId;
|
||||
let requests = 0;
|
||||
while (rawMessagesToClean.length < opts.count) {
|
||||
const potentialMessages = await targetChannel.messages.fetch({
|
||||
before: beforeId,
|
||||
limit: 100,
|
||||
});
|
||||
if (potentialMessages.size === 0) break;
|
||||
|
||||
requests++;
|
||||
|
||||
const filtered: Array<OmitPartialGroupDMChannel<Message<true>>> = [];
|
||||
for (const message of potentialMessages.values()) {
|
||||
const contentString = message.content || "";
|
||||
if (opts.authorId && message.author.id !== opts.authorId) continue;
|
||||
if (opts.onlyBotMessages && !message.author.bot) continue;
|
||||
if (pinIds.has(message.id)) continue;
|
||||
if (opts.onlyWithInvites && getInviteCodesInString(contentString).length === 0) continue;
|
||||
if (opts.upToId && message.id < opts.upToId) {
|
||||
foundId = true;
|
||||
break;
|
||||
}
|
||||
if (message.createdTimestamp < timestampCutoff) continue;
|
||||
if (opts.matchContent && !(await pluginData.state.regexRunner.exec(opts.matchContent, contentString).catch(allowTimeout))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
filtered.push(message);
|
||||
}
|
||||
const remaining = opts.count - rawMessagesToClean.length;
|
||||
const withoutOverflow = filtered.slice(0, remaining);
|
||||
rawMessagesToClean.push(...withoutOverflow);
|
||||
|
||||
beforeId = potentialMessages.lastKey()!;
|
||||
|
||||
if (foundId) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (rawMessagesToClean.length < opts.count) {
|
||||
if (potentialMessages.last()!.createdTimestamp < timestampCutoff) {
|
||||
result.note = `stopped looking after reaching ${humanizeDurationShort(MAX_CLEAN_TIME)} old messages`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (requests >= MAX_CLEAN_API_REQUESTS) {
|
||||
result.note = `stopped looking after ${requests * 100} messages`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Discord messages -> SavedMessages
|
||||
const existingStored = await pluginData.state.savedMessages.getMultiple(rawMessagesToClean.map((m) => m.id));
|
||||
const alreadyStored = existingStored.map((stored) => stored.id);
|
||||
const messagesToStore = rawMessagesToClean.filter((potentialMsg) => !alreadyStored.includes(potentialMsg.id));
|
||||
await pluginData.state.savedMessages.createFromMessages(messagesToStore);
|
||||
|
||||
result.messages = await pluginData.state.savedMessages.getMultiple(rawMessagesToClean.map((m) => m.id));
|
||||
|
||||
return result;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue