From 9f2b31d9aac7e529ecc9981b6b66f675f2429144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A6=AC=E5=89=83=20=E5=A4=A9=E6=84=9B=E6=98=9F?= <131457234+TiaraBasori@users.noreply.github.com> Date: Sat, 20 Dec 2025 20:21:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E4=BB=8E=E7=BE=A4=E9=87=8C=E9=81=93=E5=90=AC=E9=80=94=E8=AF=B4?= =?UTF-8?q?=E6=9D=A5=E7=9A=84=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 详情请咨询原作者(也不知道是谁,反正不保证可用性) --- epic/epic.ts | 168 +++++++++++++++ jupai/jupai.ts | 100 +++++++++ nezha/nezha.ts | 557 +++++++++++++++++++++++++++++++++++++++++++++++++ plugins.json | 18 +- 4 files changed, 840 insertions(+), 3 deletions(-) create mode 100644 epic/epic.ts create mode 100644 jupai/jupai.ts create mode 100644 nezha/nezha.ts diff --git a/epic/epic.ts b/epic/epic.ts new file mode 100644 index 00000000..a1fc8232 --- /dev/null +++ b/epic/epic.ts @@ -0,0 +1,168 @@ +import { Plugin } from "@utils/pluginBase"; +import { Api } from "telegram"; +import { getGlobalClient } from "@utils/globalClient"; +import { getPrefixes } from "@utils/pluginManager"; +import axios from "axios"; + +const prefixes = getPrefixes(); +const mainPrefix = prefixes[0]; + +const htmlEscape = (text: string): string => { + if (typeof text !== "string") return ""; + return text.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """).replace(/'/g, "'"); +}; + +const help_text = `⚙️ Epic 限免游戏 + +📝 功能描述: +• 获取 Epic Games 每周限免游戏信息 +• 显示游戏详情、原价、限免时间 + +🔧 使用方法: +• ${mainPrefix}epic - 查看当前限免游戏 +• ${mainPrefix}epic help - 显示帮助 + +📊 数据来源: +• Epic Games Store API`; + +// Epic API URL +const EPIC_API_URL = "https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions?locale=zh-CN&country=CN&allowCountries=CN"; + +interface EpicGame { + title: string; + description: string; + originalPrice: string; + startDate: string; + endDate: string; + url: string; + imageUrl: string; +} + +// 解析限免游戏数据 +function parseFreeGames(data: any): { current: EpicGame[]; upcoming: EpicGame[] } { + const current: EpicGame[] = []; + const upcoming: EpicGame[] = []; + + const elements = data?.data?.Catalog?.searchStore?.elements || []; + + for (const game of elements) { + // 跳过非游戏类型 + if (!game.categories?.some((c: any) => c.path === "freegames")) continue; + + const promotions = game.promotions; + if (!promotions) continue; + + // 获取游戏URL + const pageSlug = game.offerMappings?.[0]?.pageSlug || game.catalogNs?.mappings?.[0]?.pageSlug || game.productSlug || game.urlSlug; + const url = pageSlug ? `https://store.epicgames.com/zh-CN/p/${pageSlug}` : ""; + + // 获取图片 + const imageUrl = game.keyImages?.find((img: any) => img.type === "OfferImageWide" || img.type === "Thumbnail")?.url || ""; + + // 获取价格 + const price = game.price?.totalPrice; + const originalPrice = price?.fmtPrice?.originalPrice || "免费"; + + const baseInfo: Omit = { + title: game.title || "未知游戏", + description: game.description || "", + originalPrice, + url, + imageUrl, + }; + + // 当前限免 + const currentPromo = promotions.promotionalOffers?.[0]?.promotionalOffers?.[0]; + if (currentPromo && price?.discountPrice === 0) { + current.push({ + ...baseInfo, + startDate: currentPromo.startDate, + endDate: currentPromo.endDate, + }); + continue; + } + + // 即将限免 + const upcomingPromo = promotions.upcomingPromotionalOffers?.[0]?.promotionalOffers?.[0]; + if (upcomingPromo && upcomingPromo.discountSetting?.discountPercentage === 0) { + upcoming.push({ + ...baseInfo, + startDate: upcomingPromo.startDate, + endDate: upcomingPromo.endDate, + }); + } + } + + return { current, upcoming }; +} + +// 格式化日期 +function formatDate(dateStr: string): string { + try { + const date = new Date(dateStr); + return date.toLocaleString("zh-CN", { timeZone: "Asia/Shanghai", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit" }); + } catch { + return dateStr; + } +} + +// 构建游戏信息文本 +function buildGameText(game: EpicGame, index: number): string { + const title = htmlEscape(game.title); + const desc = game.description.length > 100 ? htmlEscape(game.description.slice(0, 100)) + "..." : htmlEscape(game.description); + const start = formatDate(game.startDate); + const end = formatDate(game.endDate); + const link = game.url ? `🔗 领取` : ""; + + return `${index}. ${title} +💰 原价: ${htmlEscape(game.originalPrice)}免费 +📅 ${start} ~ ${end} +${desc} +${link}`; +} + +class EpicPlugin extends Plugin { + description: string = help_text; + + cmdHandlers: Record Promise> = { + epic: async (msg: Api.Message) => { + const client = await getGlobalClient(); + if (!client) { + await msg.edit({ text: "❌ 客户端未初始化", parseMode: "html" }); + return; + } + + const parts = msg.text?.trim().split(/\s+/) || []; + const sub = (parts[1] || "").toLowerCase(); + + if (sub === "help" || sub === "h") { + await msg.edit({ text: help_text, parseMode: "html" }); + return; + } + + try { + await msg.edit({ text: "🎮 获取 Epic 限免游戏中...", parseMode: "html" }); + + const res = await axios.get(EPIC_API_URL, { timeout: 15000 }); + const { current, upcoming } = parseFreeGames(res.data); + + let text = "🎮 Epic Games 限免游戏\n\n"; + + if (current.length > 0) { + text += "📢 当前限免:\n\n"; + current.forEach((g, i) => (text += buildGameText(g, i + 1) + "\n\n")); + } else { + text += "📢 当前限免: 暂无\n\n"; + } + + await msg.edit({ text, parseMode: "html", linkPreview: false }); + } catch (error: any) { + console.error("[epic] 获取失败:", error); + await msg.edit({ text: `❌ 获取失败: ${htmlEscape(error.message || "网络错误")}`, parseMode: "html" }); + } + }, + }; +} + +export default new EpicPlugin(); + diff --git a/jupai/jupai.ts b/jupai/jupai.ts new file mode 100644 index 00000000..5e5965c7 --- /dev/null +++ b/jupai/jupai.ts @@ -0,0 +1,100 @@ +import axios from "axios"; +import { getPrefixes } from "@utils/pluginManager"; +import { Plugin } from "@utils/pluginBase"; +import { Api } from "telegram"; +import { getGlobalClient } from "@utils/globalClient"; +import { CustomFile } from "telegram/client/uploads.js"; + +const timeout = 60000; +const prefixes = getPrefixes(); +const mainPrefix = prefixes[0]; +const pluginName = "jupai"; +const commandName = `${mainPrefix}${pluginName}`; +const juPaiApi = "https://api.txqq.pro/api/zt.php"; + +const help_text = ` +生成举牌小人图片 + +${commandName} [文本] - 生成举牌小人 +或回复消息使用 ${commandName} - 将回复的消息内容生成举牌小人 + +示例: +${commandName} 你好世界 +`; + +class JuPaiPlugin extends Plugin { + description: string = `\n举牌小人\n\n${help_text}`; + + cmdHandlers: Record Promise> = { + jupai: async (msg: Api.Message) => { + try { + // 获取文本内容 + const args = msg.message.split(/\s+/).slice(1); + let text = args.join(" "); + + // 如果命令后没有文本,检查是否回复了消息 + if (!text) { + const replied = msg.replyTo ? await msg.getReplyMessage() : null; + if (replied && replied.message) { + text = replied.message; + } + } + + // 如果还是没有文本,显示帮助信息 + if (!text) { + await msg.edit({ + text: help_text, + parseMode: "html" + }); + return; + } + + await msg.edit({ text: "正在生成举牌小人..." }); + + try { + // 构建 API URL,对文本进行 URL 编码 + const imageUrl = `${juPaiApi}?msg=${encodeURIComponent(text)}`; + + // 获取图片数据 + const response = await axios.get(imageUrl, { + responseType: "arraybuffer", + timeout, + }); + + const imageBuffer = Buffer.from(response.data); + + if (!imageBuffer || imageBuffer.length === 0) { + await msg.edit({ text: "图片获取失败或为空" }); + return; + } + + // 发送图片 + const client = await getGlobalClient(); + const file = new CustomFile( + "jupai.jpg", + imageBuffer.length, + "", + imageBuffer + ); + + await client.sendFile(msg.peerId, { + file, + replyTo: msg.replyTo?.replyToMsgId || msg.id, + }); + + await msg.delete(); + } catch (error) { + const errorMsg = error instanceof Error ? error.message : String(error); + await msg.edit({ text: `获取失败: ${errorMsg}` }); + } + } catch (error) { + console.error("JuPai Plugin Error:", error); + const errorMsg = error instanceof Error ? error.message : String(error); + await msg.edit({ text: `插件执行失败: ${errorMsg}` }); + } + }, + }; +} + +export default new JuPaiPlugin(); + diff --git a/nezha/nezha.ts b/nezha/nezha.ts new file mode 100644 index 00000000..68d00c5d --- /dev/null +++ b/nezha/nezha.ts @@ -0,0 +1,557 @@ +import { Plugin } from "@utils/pluginBase"; +import { Api } from "telegram"; +import axios from "axios"; +import * as crypto from "crypto"; +import * as fs from "fs"; +import * as path from "path"; +import * as yaml from "js-yaml"; +import { createDirectoryInAssets } from "@utils/pathHelpers"; + +interface NeZhaConfig { + url: string; + secret: string; + configPath?: string; + serviceMonitor?: boolean; +} + +interface ServerHost { + platform?: string; + cpu?: string[]; + mem_total?: number; + disk_total?: number; + version?: string; +} + +interface ServerState { + cpu?: number; + mem_used?: number; + swap_used?: number; + disk_used?: number; + net_in_speed?: number; + net_out_speed?: number; + net_in_transfer?: number; + net_out_transfer?: number; + load_1?: number; + load_5?: number; + load_15?: number; + uptime?: number; + tcp_conn_count?: number; + udp_conn_count?: number; + process_count?: number; +} + +interface ServerGeoIP { + ip?: { + ipv4_addr?: string; + ipv6_addr?: string; + }; + country_code?: string; +} + +interface Server { + id: number; + name: string; + display_index?: number; + host?: ServerHost; + state?: ServerState; + geoip?: ServerGeoIP; + last_active?: string; +} + +interface ApiResponse { + success: boolean; + data?: Server[]; + error?: string; +} + +interface ServiceMonitorItem { + monitor_id: number; + server_id: number; + monitor_name: string; + server_name: string; + created_at: number[]; + avg_delay: number[]; +} + +interface ServiceMonitorData { + success: boolean; + data?: ServiceMonitorItem[]; +} + +let configCache: NeZhaConfig | null = null; +let configDir: string = ""; +let configFile: string = ""; + +function getConfigPath(): string { + if (!configDir) { + configDir = createDirectoryInAssets("nezha"); + configFile = path.join(configDir, "config.json"); + } + return configFile; +} + +function loadConfig(): NeZhaConfig | null { + if (configCache) return configCache; + try { + const file = getConfigPath(); + if (fs.existsSync(file)) { + const content = fs.readFileSync(file, "utf-8"); + configCache = JSON.parse(content); + return configCache; + } + } catch {} + return null; +} + +function saveConfig(config: NeZhaConfig): void { + try { + const file = getConfigPath(); + fs.writeFileSync(file, JSON.stringify(config, null, 2), "utf-8"); + configCache = config; + } catch (e) { + console.error("Failed to save nezha config:", e); + } +} + +function htmlEscape(text: string): string { + if (typeof text !== "string") return ""; + return text + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + +function formatBytes(bytes: number): string { + if (bytes === 0) return "0 B"; + const k = 1024; + const sizes = ["B", "KB", "MB", "GB", "TB"]; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return (bytes / Math.pow(k, i)).toFixed(2) + " " + sizes[i]; +} + +function formatSpeed(bytes: number): string { + return formatBytes(bytes) + "/s"; +} + +function formatUptime(seconds: number): string { + const days = Math.floor(seconds / 86400); + const hours = Math.floor((seconds % 86400) / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + const parts: string[] = []; + if (days > 0) parts.push(`${days}天`); + if (hours > 0) parts.push(`${hours}时`); + if (minutes > 0) parts.push(`${minutes}分`); + return parts.join("") || "0分"; +} + +function getStatusEmoji(isOnline: boolean): string { + return isOnline ? "🟢" : "🔴"; +} + +function getUsageBar(percent: number): string { + const filled = Math.round(percent / 10); + return "█".repeat(filled) + "░".repeat(10 - filled); +} + +function base64UrlEncode(data: string): string { + return Buffer.from(data) + .toString("base64") + .replace(/=/g, "") + .replace(/\+/g, "-") + .replace(/\//g, "_"); +} + +function generateJWT(secret: string, userId: string = "1"): string { + const header = { alg: "HS256", typ: "JWT" }; + const now = Math.floor(Date.now() / 1000); + const payload = { + user_id: userId, + orig_iat: now, + exp: now + 3600, + ip: "", + }; + + const headerB64 = base64UrlEncode(JSON.stringify(header)); + const payloadB64 = base64UrlEncode(JSON.stringify(payload)); + const signature = crypto + .createHmac("sha256", secret) + .update(`${headerB64}.${payloadB64}`) + .digest("base64") + .replace(/=/g, "") + .replace(/\+/g, "-") + .replace(/\//g, "_"); + + return `${headerB64}.${payloadB64}.${signature}`; +} + +function readSecretFromConfig(configPath: string): string | null { + try { + if (!fs.existsSync(configPath)) { + return null; + } + const content = fs.readFileSync(configPath, "utf-8"); + const config = yaml.load(content) as any; + return config?.jwt_secret_key || config?.jwtSecretKey || null; + } catch { + return null; + } +} + +async function fetchServers(config: NeZhaConfig): Promise { + let secret = config.secret; + + if (config.configPath) { + const fileSecret = readSecretFromConfig(config.configPath); + if (fileSecret) { + secret = fileSecret; + } + } + + const token = generateJWT(secret); + const apiUrl = config.url.replace(/\/$/, "") + "/api/v1/server"; + const response = await axios.get(apiUrl, { + timeout: 15000, + headers: { + Cookie: `nz-jwt=${token}`, + "User-Agent": "TeleBox-NeZha-Plugin/1.0", + }, + }); + + if (response.data.success && response.data.data) { + return response.data.data; + } + if (Array.isArray(response.data)) { + return response.data; + } + throw new Error((response.data as any).error || "获取服务器列表失败"); +} + +function isServerOnline(server: Server): boolean { + if (!server.last_active) return false; + const lastActive = new Date(server.last_active).getTime(); + const now = Date.now(); + return now - lastActive < 60000; +} + +async function fetchServiceMonitor( + config: NeZhaConfig, + serverId: number +): Promise> { + const result = new Map(); + try { + let secret = config.secret; + if (config.configPath) { + const fileSecret = readSecretFromConfig(config.configPath); + if (fileSecret) secret = fileSecret; + } + const token = generateJWT(secret); + const apiUrl = config.url.replace(/\/$/, "") + `/api/v1/service/${serverId}`; + const response = await axios.get(apiUrl, { + timeout: 10000, + headers: { + Cookie: `nz-jwt=${token}`, + "User-Agent": "TeleBox-NeZha-Plugin/1.0", + }, + }); + if (response.data.success && response.data.data) { + for (const item of response.data.data) { + if (item.monitor_name && item.avg_delay && item.avg_delay.length > 0) { + const latestDelay = item.avg_delay[item.avg_delay.length - 1]; + result.set(item.monitor_name, latestDelay); + } + } + } + } catch (error: any) { + console.error(`[NeZha Debug] Service monitor API error for server ${serverId}:`, error.message || error); + } + return result; +} + +function getCountryFlag(code?: string): string { + if (!code) return ""; + const flags: Record = { + us: "🇺🇸", jp: "🇯🇵", hk: "🇭🇰", sg: "🇸🇬", kr: "🇰🇷", tw: "🇹🇼", + de: "🇩🇪", gb: "🇬🇧", fr: "🇫🇷", nl: "🇳🇱", au: "🇦🇺", ca: "🇨🇦", + cn: "🇨🇳", ru: "🇷🇺", in: "🇮🇳", br: "🇧🇷", + }; + return flags[code.toLowerCase()] || ""; +} + +function formatServerInfo( + server: Server, + serviceData?: Map +): string { + const online = isServerOnline(server); + const state = server.state; + const host = server.host; + const flag = getCountryFlag(server.geoip?.country_code); + + let title = `${getStatusEmoji(online)} ${flag} ${htmlEscape(server.name)}`; + + if (serviceData && serviceData.size > 0) { + const monitors: string[] = []; + serviceData.forEach((delay, name) => { + const delayMs = delay.toFixed(1); + monitors.push(`${name}:${delayMs}ms`); + }); + title += `\n📶 ${monitors.join(" | ")}`; + } + + if (!online) { + title += ` (离线)`; + return title; + } + + if (state) { + const cpuPercent = state.cpu?.toFixed(1) || "0"; + const memPercent = + host?.mem_total && state.mem_used + ? ((state.mem_used / host.mem_total) * 100).toFixed(1) + : "0"; + const diskPercent = + host?.disk_total && state.disk_used + ? ((state.disk_used / host.disk_total) * 100).toFixed(1) + : "0"; + + let details = `├ CPU: ${getUsageBar(parseFloat(cpuPercent))} ${cpuPercent}%\n`; + details += `├ 内存: ${getUsageBar(parseFloat(memPercent))} ${memPercent}%`; + if (state.mem_used && host?.mem_total) { + details += ` (${formatBytes(state.mem_used)}/${formatBytes(host.mem_total)})`; + } + details += `\n`; + details += `├ 硬盘: ${getUsageBar(parseFloat(diskPercent))} ${diskPercent}%`; + if (state.disk_used && host?.disk_total) { + details += ` (${formatBytes(state.disk_used)}/${formatBytes(host.disk_total)})`; + } + details += `\n`; + details += `├ 网络: ↑${formatSpeed(state.net_out_speed || 0)} ↓${formatSpeed(state.net_in_speed || 0)}\n`; + details += `├ 流量: ↑${formatBytes(state.net_out_transfer || 0)} ↓${formatBytes(state.net_in_transfer || 0)}\n`; + details += `└ 运行: ${formatUptime(state.uptime || 0)}`; + + return `${title}\n
${details}
`; + } + + return title; +} + +const nezha = async (msg: Api.Message) => { + try { + const args = msg.message.slice(1).split(" ").slice(1); + const subCmd = args[0]?.toLowerCase(); + + if (subCmd === "service") { + const toggle = args[1]?.toLowerCase(); + const config = loadConfig(); + if (!config) { + await msg.edit({ + text: "❌ 请先配置哪吒监控", + parseMode: "html", + }); + return; + } + if (toggle === "on") { + config.serviceMonitor = true; + saveConfig(config); + await msg.edit({ + text: "✅ 服务监控已开启", + parseMode: "html", + }); + } else if (toggle === "off") { + config.serviceMonitor = false; + saveConfig(config); + await msg.edit({ + text: "✅ 服务监控已关闭", + parseMode: "html", + }); + } else { + const status = config.serviceMonitor !== false ? "开启" : "关闭"; + await msg.edit({ + text: `📶 服务监控当前状态: ${status}\n\n用法: nezha service on/off`, + parseMode: "html", + }); + } + return; + } + + if (subCmd === "set") { + const url = args[1]; + const secretOrPath = args[2]; + + if (!url || !secretOrPath) { + await msg.edit({ + text: `❌ 设置哪吒监控 + +用法: +nezha set [面板地址] [JWT Secret] +nezha set [面板地址] [config.yaml路径] + +示例: +nezha set https://nezha.example.com your_jwt_secret +nezha set https://nezha.example.com /opt/nezha/data/config.yaml + +说明: +• 可直接填写 jwt_secret_key +• 或填写 config.yaml 路径,自动读取 secret`, + parseMode: "html", + }); + return; + } + + let config: NeZhaConfig; + let secret: string; + + if ( + secretOrPath.endsWith(".yaml") || + secretOrPath.endsWith(".yml") || + secretOrPath.startsWith("/") + ) { + const fileSecret = readSecretFromConfig(secretOrPath); + if (!fileSecret) { + await msg.edit({ + text: `❌ 配置文件读取失败 + +无法从 ${htmlEscape(secretOrPath)} 读取 jwt_secret_key + +请检查文件路径是否正确`, + parseMode: "html", + }); + return; + } + secret = fileSecret; + config = { url, secret, configPath: secretOrPath }; + } else { + secret = secretOrPath; + config = { url, secret }; + } + + await msg.edit({ text: "🔍 正在验证配置..." }); + + try { + await fetchServers(config); + saveConfig(config); + await msg.edit({ + text: `✅ 哪吒监控配置成功 + +面板地址: ${htmlEscape(url)} +认证方式: ${config.configPath ? "配置文件自动读取" : "JWT Secret"} + +使用 nezha 查看服务器状态`, + parseMode: "html", + }); + } catch (error: any) { + await msg.edit({ + text: `❌ 配置验证失败 + +错误: ${htmlEscape(error.message)} + +请检查面板地址和 Secret 是否正确`, + parseMode: "html", + }); + } + return; + } + + const config = loadConfig(); + + if (!config) { + await msg.edit({ + text: `📊 哪吒监控插件 + +首次使用请先配置: +nezha set [面板地址] [JWT Secret] +nezha set [面板地址] [config.yaml路径] + +示例: +nezha set https://nezha.example.com your_secret +nezha set https://nezha.example.com /opt/nezha/data/config.yaml`, + parseMode: "html", + }); + return; + } + + await msg.edit({ text: "🔍 正在获取服务器状态..." }); + + const servers = await fetchServers(config); + + const serviceDataMap = new Map>(); + if (config.serviceMonitor !== false) { + const onlineServers = servers.filter(isServerOnline); + await Promise.all( + onlineServers.map(async (server) => { + const data = await fetchServiceMonitor(config, server.id); + if (data.size > 0) { + serviceDataMap.set(server.id, data); + } + }) + ); + } + + if (!servers.length) { + await msg.edit({ + text: "📊 哪吒监控\n\n暂无服务器数据", + parseMode: "html", + }); + return; + } + + servers.sort((a, b) => { + const aOnline = isServerOnline(a); + const bOnline = isServerOnline(b); + if (aOnline !== bOnline) return bOnline ? 1 : -1; + return (a.display_index || 0) - (b.display_index || 0); + }); + + const onlineCount = servers.filter(isServerOnline).length; + const totalCount = servers.length; + + let resultText = `📊 哪吒监控 (${onlineCount}/${totalCount} 在线)\n\n`; + resultText += servers + .map((s) => formatServerInfo(s, serviceDataMap.get(s.id))) + .join("\n\n"); + + if (resultText.length > 4000) { + const onlineOnly = servers.filter(isServerOnline); + resultText = `📊 哪吒监控 (${onlineCount}/${totalCount} 在线)\n\n`; + resultText += onlineOnly + .map((s) => formatServerInfo(s, serviceDataMap.get(s.id))) + .join("\n\n"); + + if (totalCount - onlineCount > 0) { + resultText += `\n\n🔴 还有 ${totalCount - onlineCount} 台服务器离线`; + } + } + + await msg.edit({ + text: resultText, + parseMode: "html", + }); + } catch (error: any) { + console.error("NeZha plugin error:", error); + await msg.edit({ + text: `❌ 获取失败 + +错误: ${htmlEscape(error.message || "未知错误")} + +请检查网络连接或重新配置`, + parseMode: "html", + }); + } +}; + +class NeZhaPlugin extends Plugin { + description: string = ` +哪吒监控插件: +- nezha - 查看所有服务器状态 +- nezha set [地址] [Secret/配置文件路径] - 配置哪吒面板 +- nezha service on/off - 开启/关闭服务监控显示 + +支持直接填写 jwt_secret_key 或 config.yaml 路径自动读取 + `; + cmdHandlers: Record Promise> = { + nezha, + }; +} + +export default new NeZhaPlugin(); diff --git a/plugins.json b/plugins.json index 6101f441..f735e43d 100644 --- a/plugins.json +++ b/plugins.json @@ -391,8 +391,20 @@ "url": "https://github.com/TeleBoxOrg/TeleBox_Plugins/blob/main/prometheus/prometheus.ts?raw=true", "desc": "突破Telegram保存限制" }, - "autorepeat": { - "url": "https://github.com/TeleBoxOrg/TeleBox_Plugins/blob/main/autorepeat/autorepeat.ts?raw=true", - "desc": "智能自动复读机" + "autorepeat": { + "url": "https://github.com/TeleBoxOrg/TeleBox_Plugins/blob/main/autorepeat/autorepeat.ts?raw=true", + "desc": "智能自动复读机" + }, + "epic": { + "url": "https://github.com/TeleBoxOrg/TeleBox_Plugins/blob/main/epic/epic.ts?raw=true", + "desc": "检查Epic Games喜加一优惠" + }, + "nezha": { + "url": "https://github.com/TeleBoxOrg/TeleBox_Plugins/blob/main/nezha/nezha.ts?raw=true", + "desc": "哪吒监控" + }, + "jupai": { + "url": "https://github.com/TeleBoxOrg/TeleBox_Plugins/blob/main/jupai/jupai.ts?raw=true", + "desc": "举牌小人" } }