Update from Git Manager GUI

This commit is contained in:
2026-02-25 18:51:08 +01:00
parent de4341a0a9
commit 1567151fce
21 changed files with 2023 additions and 0 deletions

130
commands/compare.js Normal file
View File

@@ -0,0 +1,130 @@
import { EmbedBuilder, SlashCommandBuilder } from "discord.js";
import fs from "fs";
import { t, getLang } from "../util/i18n.js";
import { generateResourceIconURL } from "../util/helpers.js";
import { Spiget } from "spiget";
const spiget = new Spiget("Viper-Network");
export default {
name: "compare",
description: "Vergleicht zwei Plugins nebeneinander",
aliases: ["cmp"],
guild: ["all"],
nsfw: false,
user_permissions: [],
bot_permissions: [],
args_required: 2,
args_usage: "[id1] [id2] Beispiel: vn!compare 72678 34315",
cooldown: 10,
data: new SlashCommandBuilder()
.setName("compare")
.setDescription("Compares two plugins side by side")
.addStringOption((opt) =>
opt.setName("id1").setDescription("Erste Ressourcen-ID").setRequired(true)
)
.addStringOption((opt) =>
opt.setName("id2").setDescription("Zweite Ressourcen-ID").setRequired(true)
),
async execute(client, ctx, args) {
const lang = loadLang(ctx.guild.id);
const id1 = ctx.isSlash ? ctx.interaction.options.getString("id1") : args[0];
const id2 = ctx.isSlash ? ctx.interaction.options.getString("id2") : args[1];
// Fetch both resources in parallel
let [dataA, dataB] = await Promise.all([
fetchResource(id1),
fetchResource(id2),
]);
if (!dataA) return ctx.reply(t(lang, "error.invalidID", { id: id1 }));
if (!dataB) return ctx.reply(t(lang, "error.invalidID", { id: id2 }));
// Fetch latest versions
const [verA, verB] = await Promise.all([
fetchVersion(id1),
fetchVersion(id2),
]);
dataA.latestVersion = verA;
dataB.latestVersion = verB;
// Helper: format a stat with winner indicator
const win = (valA, valB, higherIsBetter = true) => {
if (valA === valB) return ["", ""];
const aWins = higherIsBetter ? valA > valB : valA < valB;
return aWins ? ["🏆", ""] : ["", "🏆"];
};
const [dlWinA, dlWinB] = win(dataA.downloads, dataB.downloads);
const [rtWinA, rtWinB] = win(dataA.rating?.average ?? 0, dataB.rating?.average ?? 0);
const dateA = dataA.updateDate ? new Date(dataA.updateDate * 1000).toLocaleDateString("de-DE") : "?";
const dateB = dataB.updateDate ? new Date(dataB.updateDate * 1000).toLocaleDateString("de-DE") : "?";
const [dtWinA, dtWinB] = win(dataA.updateDate ?? 0, dataB.updateDate ?? 0);
const dlA = (dataA.downloads ?? 0).toLocaleString("de-DE");
const dlB = (dataB.downloads ?? 0).toLocaleString("de-DE");
const rtA = dataA.rating?.average?.toFixed(1) ?? "";
const rtB = dataB.rating?.average?.toFixed(1) ?? "";
const embed = new EmbedBuilder()
.setColor(ctx.guild.members.me.displayHexColor)
.setTitle(t(lang, "compare.title"))
.addFields([
// Header row
{ name: "📦 Plugin", value: `**${dataA.name}**`, inline: true },
{ name: "\u200b", value: "**vs**", inline: true },
{ name: "\u200b", value: `**${dataB.name}**`, inline: true },
// Downloads
{ name: t(lang, "compare.downloads"), value: `${dlWinA} ${dlA}`, inline: true },
{ name: "\u200b", value: "⬇️", inline: true },
{ name: "\u200b", value: `${dlWinB} ${dlB}`, inline: true },
// Rating
{ name: t(lang, "compare.rating"), value: `${rtWinA}${rtA}`, inline: true },
{ name: "\u200b", value: "⭐", inline: true },
{ name: "\u200b", value: `${rtWinB}${rtB}`, inline: true },
// Version
{ name: t(lang, "compare.version"), value: `v${verA ?? "?"}`, inline: true },
{ name: "\u200b", value: "📦", inline: true },
{ name: "\u200b", value: `v${verB ?? "?"}`, inline: true },
// Last update
{ name: t(lang, "compare.updated"), value: `${dtWinA} ${dateA}`, inline: true },
{ name: "\u200b", value: "🕐", inline: true },
{ name: "\u200b", value: `${dtWinB} ${dateB}`, inline: true },
// Links
{ name: "🔗 Link", value: `[SpigotMC](https://spigotmc.org/resources/.${id1}/)`, inline: true },
{ name: "\u200b", value: "\u200b", inline: true },
{ name: "\u200b", value: `[SpigotMC](https://spigotmc.org/resources/.${id2}/)`, inline: true },
])
.setFooter({ text: `IDs: ${id1} vs ${id2}` })
.setTimestamp();
return ctx.reply({ embeds: [embed] });
},
};
async function fetchResource(id) {
try {
const res = await fetch(`https://api.spiget.org/v2/resources/${id}`);
if (!res.ok) return null;
return await res.json();
} catch { return null; }
}
async function fetchVersion(id) {
try {
const res = await fetch(`https://api.spigotmc.org/legacy/update.php?resource=${id}`);
if (!res.ok) return null;
return (await res.text()).trim();
} catch { return null; }
}
function loadLang(guildID) {
try {
const data = JSON.parse(fs.readFileSync(`./serverdata/${guildID}.json`, "utf8"));
return getLang(data);
} catch { return "de"; }
}