import { EmbedBuilder, PermissionsBitField, SlashCommandBuilder } from "discord.js"; import fs from "fs/promises"; import { Spiget } from "spiget"; import { generateAvatarLink, generateAuthorURL, generateResourceIconURL, getLatestVersion, getUpdateDescription, } from "../util/helpers.js"; const spiget = new Spiget("Viper-Network"); export default { name: "update", description: "Führt manuell einen Update-Check für eine bestimmte Ressource durch", aliases: [], guild: ["all"], nsfw: false, user_permissions: [PermissionsBitField.Flags.Administrator], bot_permissions: [], args_required: 1, args_usage: "[ressourcen_id] Beispiel: vn!update 72678", cooldown: 10, data: new SlashCommandBuilder() .setName("update") .setDescription("Manueller Update-Check für eine Ressource") .addStringOption((opt) => opt.setName("ressourcen_id").setDescription("Spiget Ressourcen-ID").setRequired(true) ), async execute(client, ctx, args) { const resourceID = ctx.isSlash ? ctx.interaction.options.getString("ressourcen_id") : args[0]; const guildID = ctx.guild.id; const filePath = `./serverdata/${guildID}.json`; // Load server data let saveData; try { const raw = await fs.readFile(filePath, "utf8"); saveData = JSON.parse(raw); } catch { return ctx.reply("Dieser Server hat keine beobachteten Ressourcen."); } const watched = saveData.watchedResources.find( (r) => String(r.resourceID) === String(resourceID) ); if (!watched) { return ctx.reply( `Ressource \`${resourceID}\` wird auf diesem Server nicht beobachtet. Füge sie zuerst mit \`${client.config.prefix}add\` hinzu.` ); } // Fetch resource info let resource, author; try { resource = await spiget.getResource(resourceID); author = await resource.getAuthor(); } catch (e) { client.logger.error(e); return ctx.reply("Ressourcen-Informationen konnten nicht abgerufen werden."); } let latestVersion; try { latestVersion = await getLatestVersion(resourceID); } catch (e) { client.logger.error(e); return ctx.reply("Version konnte nicht abgerufen werden."); } const previousVersion = watched.lastCheckedVersion; const hasUpdate = previousVersion !== latestVersion; const authorURL = generateAuthorURL(author.name, author.id); const authorAvatarURL = generateAvatarLink(author.id); const resourceIconURL = generateResourceIconURL(resource); const resourceURL = `https://spigotmc.org/resources/.${resourceID}/`; if (!hasUpdate) { const upToDateEmbed = new EmbedBuilder() .setAuthor({ name: `Autor: ${author.name}`, iconURL: authorAvatarURL, url: authorURL }) .setColor("#00FF00") .setTitle(`✅ ${resource.name} ist aktuell`) .setDescription(resource.tag) .addFields([ { name: "Version", value: `**${latestVersion}**`, inline: true }, { name: "Status", value: "Kein Update verfügbar", inline: true }, ]) .setThumbnail(resourceIconURL) .setTimestamp(); return ctx.reply({ embeds: [upToDateEmbed] }); } // Update available let updateDesc; try { updateDesc = await getUpdateDescription(resourceID); } catch { updateDesc = "Update-Beschreibung konnte nicht abgerufen werden."; } const updateEmbed = new EmbedBuilder() .setAuthor({ name: `Autor: ${author.name}`, iconURL: authorAvatarURL, url: authorURL }) .setColor("#FFA500") .setTitle(`🔔 Update verfügbar: ${resource.name}`) .setDescription(resource.tag) .addFields([ { name: "📦 Version", value: `~~${previousVersion}~~ → **${latestVersion}**`, inline: false, }, { name: "📝 Update-Beschreibung", value: updateDesc, inline: false }, { name: "⬇️ Download", value: resourceURL, inline: false }, ]) .setThumbnail(resourceIconURL) .setTimestamp(); // Update saved version watched.lastCheckedVersion = latestVersion; try { await fs.writeFile(filePath, JSON.stringify(saveData, null, 2)); } catch (e) { client.logger.error(e); } // Also send to the watched channel if different from current const watchedChannel = ctx.guild.channels.cache.get(watched.channelID); if (watchedChannel && watchedChannel.id !== ctx.channel.id) { watchedChannel.send({ embeds: [updateEmbed] }).catch(client.logger.error); } return ctx.reply({ embeds: [updateEmbed] }); }, };