Update from Git Manager GUI
This commit is contained in:
216
commands/addauthor.js
Normal file
216
commands/addauthor.js
Normal file
@@ -0,0 +1,216 @@
|
||||
import {
|
||||
EmbedBuilder,
|
||||
PermissionsBitField,
|
||||
SlashCommandBuilder,
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
} from "discord.js";
|
||||
import fs from "fs/promises";
|
||||
|
||||
export default {
|
||||
name: "addauthor",
|
||||
description: "Fügt alle Plugins eines SpigotMC-Autors zur Beobachtungsliste hinzu",
|
||||
aliases: ["addall"],
|
||||
guild: ["all"],
|
||||
nsfw: false,
|
||||
user_permissions: [PermissionsBitField.Flags.Administrator],
|
||||
bot_permissions: [],
|
||||
args_required: 2,
|
||||
args_usage: "[author_id] [#kanal] Beispiel: vn!addauthor 618600 #plugin-updates",
|
||||
cooldown: 10,
|
||||
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("addauthor")
|
||||
.setDescription("Fügt alle Plugins eines SpigotMC-Autors zur Beobachtungsliste hinzu")
|
||||
.addStringOption((opt) =>
|
||||
opt
|
||||
.setName("author_id")
|
||||
.setDescription("SpigotMC Autor-ID (aus der Profil-URL)")
|
||||
.setRequired(true)
|
||||
)
|
||||
.addChannelOption((opt) =>
|
||||
opt
|
||||
.setName("kanal")
|
||||
.setDescription("Kanal für Update-Benachrichtigungen")
|
||||
.setRequired(true)
|
||||
),
|
||||
|
||||
async execute(client, ctx, args) {
|
||||
const authorID = ctx.isSlash
|
||||
? ctx.interaction.options.getString("author_id")
|
||||
: args[0];
|
||||
|
||||
const channel = ctx.isSlash
|
||||
? ctx.interaction.options.getChannel("kanal")
|
||||
: ctx.mentions?.channels?.first();
|
||||
|
||||
if (!channel) {
|
||||
return ctx.reply("Dieser Kanal ist ungültig. Bitte erwähne einen Kanal auf diesem Server.");
|
||||
}
|
||||
if (!ctx.guild.channels.cache.has(channel.id)) {
|
||||
return ctx.reply("Dieser Kanal befindet sich nicht auf diesem Server!");
|
||||
}
|
||||
|
||||
// Fetch author info
|
||||
let authorName = authorID;
|
||||
try {
|
||||
const res = await fetch(`https://api.spiget.org/v2/authors/${authorID}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
authorName = data.name ?? authorID;
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
|
||||
// Fetch all resources by author
|
||||
let resources;
|
||||
try {
|
||||
const res = await fetch(
|
||||
`https://api.spiget.org/v2/authors/${authorID}/resources?size=50&sort=-updateDate`
|
||||
);
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
resources = await res.json();
|
||||
} catch (e) {
|
||||
client.logger.error(e);
|
||||
return ctx.reply("Ressourcen konnten nicht von der Spiget-API abgerufen werden. Bitte versuche es erneut.");
|
||||
}
|
||||
|
||||
if (!Array.isArray(resources) || resources.length === 0) {
|
||||
return ctx.reply(`Für Autor \`${authorID}\` wurden keine Ressourcen gefunden.`);
|
||||
}
|
||||
|
||||
const guildID = ctx.guild.id;
|
||||
const filePath = `./serverdata/${guildID}.json`;
|
||||
|
||||
// Load existing data
|
||||
let saveData = { watchedResources: [] };
|
||||
try {
|
||||
const raw = await fs.readFile(filePath, "utf8");
|
||||
saveData = JSON.parse(raw);
|
||||
} catch { /* Datei existiert noch nicht */ }
|
||||
|
||||
// Filter out already watched and check limit
|
||||
const alreadyWatched = resources.filter((r) =>
|
||||
saveData.watchedResources.some((w) => String(w.resourceID) === String(r.id))
|
||||
);
|
||||
const toAdd = resources.filter((r) =>
|
||||
!saveData.watchedResources.some((w) => String(w.resourceID) === String(r.id))
|
||||
);
|
||||
|
||||
const willAdd = toAdd;
|
||||
|
||||
if (willAdd.length === 0 && alreadyWatched.length > 0) {
|
||||
return ctx.reply(
|
||||
`Alle ${alreadyWatched.length} Ressourcen von **${authorName}** werden bereits beobachtet.`
|
||||
);
|
||||
}
|
||||
|
||||
if (willAdd.length === 0) {
|
||||
return ctx.reply("Es gibt keine neuen Ressourcen zum Hinzufügen.");
|
||||
}
|
||||
|
||||
// Build confirmation embed
|
||||
const resourceList = willAdd
|
||||
.map((r) => `• **${r.name}** (\`${r.id}\`)`)
|
||||
.join("\n");
|
||||
|
||||
const warnings = [];
|
||||
if (alreadyWatched.length > 0)
|
||||
warnings.push(`⚠️ ${alreadyWatched.length} bereits beobachtet (übersprungen)`);
|
||||
|
||||
const confirmEmbed = new EmbedBuilder()
|
||||
.setColor(ctx.guild.members.me.displayHexColor)
|
||||
.setTitle(`📦 Alle Plugins von ${authorName} beobachten`)
|
||||
.setDescription(
|
||||
`Folgende **${willAdd.length}** Ressourcen werden in <#${channel.id}> beobachtet:\n\n${resourceList}` +
|
||||
(warnings.length > 0 ? `\n\n${warnings.join("\n")}` : "")
|
||||
)
|
||||
.setFooter({ text: `Autor-ID: ${authorID} • SpigotMC` })
|
||||
.setTimestamp();
|
||||
|
||||
const row = new ActionRowBuilder().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId("addauthor_confirm")
|
||||
.setLabel(`✅ Alle ${willAdd.length} hinzufügen`)
|
||||
.setStyle(ButtonStyle.Success),
|
||||
new ButtonBuilder()
|
||||
.setCustomId("addauthor_cancel")
|
||||
.setLabel("❌ Abbrechen")
|
||||
.setStyle(ButtonStyle.Danger)
|
||||
);
|
||||
|
||||
const confirmMsg = await ctx.reply({ embeds: [confirmEmbed], components: [row], fetchReply: true });
|
||||
|
||||
// Wait for button click (30 seconds)
|
||||
let btnInteraction;
|
||||
try {
|
||||
btnInteraction = await confirmMsg.awaitMessageComponent({
|
||||
filter: (i) => i.user.id === ctx.author.id,
|
||||
time: 30_000,
|
||||
});
|
||||
} catch {
|
||||
const timeoutEmbed = EmbedBuilder.from(confirmEmbed)
|
||||
.setColor("#808080")
|
||||
.setDescription("⏱️ Zeit abgelaufen – Befehl wurde abgebrochen.");
|
||||
return confirmMsg.edit({ embeds: [timeoutEmbed], components: [] });
|
||||
}
|
||||
|
||||
if (btnInteraction.customId === "addauthor_cancel") {
|
||||
const cancelEmbed = EmbedBuilder.from(confirmEmbed)
|
||||
.setColor("#FF0000")
|
||||
.setDescription("❌ Abgebrochen.");
|
||||
return btnInteraction.update({ embeds: [cancelEmbed], components: [] });
|
||||
}
|
||||
|
||||
// Defer immediately – version fetching can take longer than 3 seconds
|
||||
await btnInteraction.deferUpdate();
|
||||
|
||||
// Fetch latest versions and save
|
||||
const added = [];
|
||||
const failed = [];
|
||||
|
||||
for (const resource of willAdd) {
|
||||
let latestVersion = "unbekannt";
|
||||
try {
|
||||
const res = await fetch(`https://api.spigotmc.org/legacy/update.php?resource=${resource.id}`);
|
||||
if (res.ok) latestVersion = (await res.text()).trim();
|
||||
} catch { /* ignore – speichern ohne Version */ }
|
||||
|
||||
saveData.watchedResources.push({
|
||||
resourceID: resource.id,
|
||||
resourceName: resource.name,
|
||||
channelID: channel.id,
|
||||
lastCheckedVersion: latestVersion,
|
||||
});
|
||||
|
||||
added.push(`✅ **${resource.name}** (v${latestVersion})`);
|
||||
|
||||
// Rate limiting
|
||||
await new Promise((r) => setTimeout(r, 300));
|
||||
}
|
||||
|
||||
try {
|
||||
await fs.mkdir("./serverdata", { recursive: true });
|
||||
await fs.writeFile(filePath, JSON.stringify(saveData, null, 2));
|
||||
} catch (e) {
|
||||
client.logger.error(e);
|
||||
return btnInteraction.editReply({
|
||||
content: "Beim Speichern der Daten ist ein Fehler aufgetreten.",
|
||||
components: [],
|
||||
});
|
||||
}
|
||||
|
||||
const successEmbed = new EmbedBuilder()
|
||||
.setColor("#00FF00")
|
||||
.setTitle(`✅ ${added.length} Plugins von ${authorName} werden jetzt beobachtet`)
|
||||
.setDescription(added.join("\n"))
|
||||
.addFields([
|
||||
{ name: "📢 Kanal", value: `<#${channel.id}>`, inline: true },
|
||||
{ name: "📊 Gesamt", value: `${saveData.watchedResources.length} beobachtet`, inline: true },
|
||||
])
|
||||
.setFooter({ text: `Autor-ID: ${authorID}` })
|
||||
.setTimestamp();
|
||||
|
||||
return btnInteraction.editReply({ embeds: [successEmbed], components: [] });
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user