130 lines
5.2 KiB
JavaScript
130 lines
5.2 KiB
JavaScript
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"; }
|
||
} |