Files
NitroSniper/index.tsx

141 lines
4.0 KiB
TypeScript
Raw Normal View History

2025-12-15 21:01:50 -05:00
/*
Made with by neoarz
I am not responsible for any damage caused by this plugin; use at your own risk
Vencord does not endorse/support this plugin (Works with Equicord as well)
dm @neoarz if u need help or have any questions
https://github.com/neoarz/NitroSniper
*/
import { Devs } from "@utils/constants";
import { Logger } from "@utils/Logger";
2026-04-22 22:02:36 -04:00
import definePlugin from "@utils/types";
import { Message } from "@vencord/discord-types";
import { findByPropsLazy } from "@webpack";
import { UserStore } from "@webpack/common";
2025-12-15 21:01:50 -05:00
2026-04-22 22:02:36 -04:00
import { settings } from "./settings";
import type { ClaimRequest, WebhookResult } from "./types";
2026-04-22 22:02:36 -04:00
import { sendClaimWebhook } from "./webhook";
const GIFT_LINK_REGEX = /(?:discord\.gift\/|discord\.com\/gifts?\/)([a-zA-Z0-9]{16,24})/;
2025-12-15 21:01:50 -05:00
const logger = new Logger("NitroSniper");
const GiftActions = findByPropsLazy("redeemGiftCode");
let startTime = 0;
let claiming = false;
2026-04-22 22:02:36 -04:00
const claimQueue: ClaimRequest[] = [];
function resetState() {
startTime = Date.now();
2026-04-22 22:02:36 -04:00
claimQueue.length = 0;
claiming = false;
}
function toError(error: unknown) {
return error instanceof Error ? error : new Error(String(error));
}
2026-04-22 22:02:36 -04:00
function isOwnMessage(message: Message) {
return message.author?.id === UserStore.getCurrentUser()?.id;
}
function shouldSkipMessage(message: Message) {
return settings.store.ignoreOwnGiftLinks && isOwnMessage(message);
}
function isMessageOlderThanStart(message: Message) {
return new Date(message.timestamp).getTime() < startTime;
}
function extractGiftCode(content: string) {
return content.match(GIFT_LINK_REGEX)?.[1] ?? null;
}
function createClaimRequest(message: Message): ClaimRequest | null {
const code = message.content ? extractGiftCode(message.content) : null;
if (!code) return null;
const authorId = message.author?.id;
const authorAvatar = message.author?.avatar;
2026-04-22 22:02:36 -04:00
return {
code,
authorId,
2026-04-22 22:02:36 -04:00
authorName: message.author?.globalName ?? message.author?.username,
authorUsername: message.author?.username,
authorAvatarUrl: authorId && authorAvatar
? `https://cdn.discordapp.com/avatars/${authorId}/${authorAvatar}.png?size=128`
: undefined,
2026-04-22 22:02:36 -04:00
channelId: message.channel_id,
guildId: message.guild_id,
messageId: message.id
};
}
function notifyClaim(result: WebhookResult, request: ClaimRequest) {
void sendClaimWebhook(
settings.store.webhookUrl,
result,
request
).catch(webhookError => {
logger.error("Failed to send NitroSniper webhook notification", webhookError);
});
}
function continueQueue() {
claiming = false;
processQueue();
}
function handleClaimSuccess(request: ClaimRequest) {
logger.log(`Successfully redeemed code: ${request.code}`);
notifyClaim("claimed", request);
continueQueue();
}
function handleClaimFailure(request: ClaimRequest, error: Error) {
logger.error(`Failed to redeem code: ${request.code}`, error);
notifyClaim("failed", request);
continueQueue();
}
function processQueue() {
2026-04-22 22:02:36 -04:00
if (claiming) return;
2026-04-22 22:02:36 -04:00
const request = claimQueue.shift();
if (!request) return;
2026-04-22 22:02:36 -04:00
claiming = true;
GiftActions.redeemGiftCode({
2026-04-22 22:02:36 -04:00
code: request.code,
onRedeemed: () => handleClaimSuccess(request),
onError: (error: unknown) => handleClaimFailure(request, toError(error))
});
}
2025-12-15 21:01:50 -05:00
export default definePlugin({
name: "NitroSniper",
description: "Automatically redeems Nitro gift links sent in chat",
authors: [Devs.neoarz],
tags: ["Chat", "Utility"],
searchTerms: ["nitro", "gift", "redeem", "snipe"],
settings,
2025-12-15 21:01:50 -05:00
start() {
resetState();
2025-12-15 21:01:50 -05:00
},
flux: {
2026-04-22 22:02:36 -04:00
MESSAGE_CREATE({ message }: { message: Message; }) {
if (!message.content || shouldSkipMessage(message) || isMessageOlderThanStart(message)) return;
2026-04-22 22:02:36 -04:00
const request = createClaimRequest(message);
if (!request) return;
2026-04-22 22:02:36 -04:00
claimQueue.push(request);
processQueue();
2025-12-15 21:01:50 -05:00
}
}
});