n1cat-discord-script-manager
Version:
A Discord.js plugin for dynamic script management and execution
244 lines (216 loc) • 7.75 kB
JavaScript
const {
SlashCommandBuilder,
PermissionFlagsBits,
EmbedBuilder,
} = require("discord.js");
const fs = require("fs");
const Logger = require("../utils/logger");
module.exports = {
data: new SlashCommandBuilder()
.setName("previewscript")
.setDescription("預覽腳本詳細信息")
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
.addStringOption((option) =>
option
.setName("scriptname")
.setDescription("要預覽的腳本名稱")
.setRequired(true)
.setAutocomplete(true)
),
async execute(interaction) {
const logger = Logger.createContextLogger({
module: "PreviewScript",
debug: interaction.client.config?.debug || false,
});
try {
const scriptName = interaction.options.getString("scriptname");
const scriptManager = interaction.client.scriptManager;
if (!scriptManager) {
return interaction.reply({
content: "❌ 找不到腳本管理器",
ephemeral: true,
});
}
const script = scriptManager.scripts.get(scriptName);
if (!script) {
return interaction.reply({
content: `❌ 找不到腳本:${scriptName}`,
ephemeral: true,
});
}
// 讀取腳本文件內容
let scriptContent = "";
try {
scriptContent = fs.readFileSync(script.path, "utf8");
} catch (error) {
logger.error(`讀取腳本文件失敗: ${error.message}`);
return interaction.reply({
content: `❌ 無法讀取腳本文件:${error.message}`,
ephemeral: true,
});
}
// 從腳本頭部註釋中提取元數據
const headerMatch = scriptContent.match(/\/\*\n([\s\S]*?)\*\//);
const headerComment = headerMatch ? headerMatch[1].trim() : "";
// 解析頭部註釋中的元數據
const metadataFallback = {
originalFileName: "未知",
author: "未知",
createdAt: "未知",
description: "暫無描述",
attachmentUrl: null,
};
// 從頭部註釋中提取元數據
const extractMetadata = (comment) => {
const metadata = { ...metadataFallback };
// 嘗試解析原始腳本名稱(支持新舊兩種格式)
const originalFileNameMatch =
comment.match(/原始腳本名稱:\s*(.+)/) ||
comment.match(/原始檔案:\s*(.+)/);
if (originalFileNameMatch)
metadata.originalFileName = originalFileNameMatch[1].trim();
const authorMatch = comment.match(/由\s*(.+?)\s*在/);
if (authorMatch) metadata.author = authorMatch[1].trim();
const createdAtMatch = comment.match(
/在\s*(\d{4}\/\d{2}\/\d{2}\s*\d{2}:\d{2}:\d{2})\s*\(UTC\)/
);
if (createdAtMatch) metadata.createdAt = createdAtMatch[1].trim();
const descriptionMatch = comment.match(/腳本描述:\s*(.+)/);
if (descriptionMatch) metadata.description = descriptionMatch[1].trim();
const attachmentUrlMatch = comment.match(/原始附件鏈接:\s*(.+)/);
if (attachmentUrlMatch && attachmentUrlMatch[1] !== "N/A") {
metadata.attachmentUrl = attachmentUrlMatch[1].trim();
}
return metadata;
};
// 合併現有元數據和從頭部提取的元數據
const mergedMetadata = {
...metadataFallback,
...script.metadata,
...extractMetadata(headerComment),
};
// 創建嵌入消息
const embed = new EmbedBuilder()
.setColor(0x00ae86)
.setTitle(`腳本預覽:${scriptName}`)
.setDescription("腳本詳細信息")
.addFields(
{
name: "原始腳本名稱",
value: mergedMetadata.originalFileName,
inline: true,
},
{
name: "上傳者",
value:
typeof mergedMetadata.author === "object" &&
mergedMetadata.author.id
? `${mergedMetadata.author.name || "未知"} (${
mergedMetadata.author.id
})`
: mergedMetadata.author || "未知",
inline: true,
},
{
name: "上傳時間",
value: mergedMetadata.createdAt,
inline: true,
},
{
name: "腳本狀態",
value: script.enabled ? "已啟用" : "已停用",
inline: true,
},
{
name: "腳本描述",
value: mergedMetadata.description,
inline: false,
}
)
.setFooter({ text: "腳本詳細信息" });
// 如果有附件鏈接,添加到 embed
if (mergedMetadata.attachmentUrl) {
embed.addFields({
name: "原始附件",
value: mergedMetadata.attachmentUrl,
inline: false,
});
}
// 預覽腳本前幾行
const previewLines = scriptContent.split("\n").slice(0, 10).join("\n");
embed.addFields({
name: "腳本預覽",
value: `\`\`\`js\n${previewLines}\n...\`\`\``,
inline: false,
});
await interaction.reply({
embeds: [embed],
ephemeral: false,
});
} catch (error) {
logger.error(`預覽腳本時出錯: ${error.message}`, { showStack: true });
await interaction.reply({
content: `❌ 預覽腳本時出錯:${error.message}`,
ephemeral: true,
});
}
},
async autocomplete(interaction) {
const logger = Logger.createContextLogger({
module: "PreviewScript",
debug: interaction.client.config?.debug || false,
});
try {
logger.log("開始處理自動完成請求");
const scriptManager = interaction.client.scriptManager;
if (!scriptManager) {
logger.error("找不到腳本管理器");
return await interaction.respond([]);
}
const focusedValue = interaction.options.getFocused().toLowerCase();
logger.log(`搜尋腳本: ${focusedValue}`);
// 獲取所有腳本並轉換為選項
const scripts = Array.from(scriptManager.scripts.entries())
.map(([name, script]) => ({
name: `${name} (${script.enabled === false ? "已停用" : "啟用中"})`,
value: name,
}))
.filter(
(script) =>
script.value.toLowerCase().includes(focusedValue) ||
script.name.toLowerCase().includes(focusedValue)
);
logger.log(`找到的腳本: ${scripts.map((s) => s.value).join(", ")}`);
await interaction.respond(scripts.slice(0, 25));
logger.log("自動完成請求處理完成");
} catch (error) {
logger.error(`自動完成時出錯: ${error.message}`, { showStack: true });
console.error("詳細錯誤信息:", {
error: error.message,
code: error.code,
interactionId: interaction.id,
interactionState: {
replied: interaction.replied,
deferred: interaction.deferred,
},
timestamp: new Date().toISOString(),
});
try {
await interaction.respond([]);
logger.log("已發送空的自動完成回應");
} catch (e) {
logger.error(`回應自動完成時出錯: ${e.message}`, { showStack: true });
console.error("發送自動完成回應時的詳細錯誤:", {
error: e.message,
code: e.code,
interactionId: interaction.id,
interactionState: {
replied: interaction.replied,
deferred: interaction.deferred,
},
timestamp: new Date().toISOString(),
});
}
}
},
};