From db64493f5d66ea2912f099bf971ff6ffd9b6895c Mon Sep 17 00:00:00 2001 From: hachem Date: Sun, 23 Nov 2025 04:44:40 +0100 Subject: [add]: i learnt how to read --- bot/app.js | 316 ++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 179 insertions(+), 137 deletions(-) diff --git a/bot/app.js b/bot/app.js index 8f1bfeb..d0d5084 100644 --- a/bot/app.js +++ b/bot/app.js @@ -1,161 +1,203 @@ - const { Client, Events, GatewayIntentBits } = require("discord.js") - const axios = require("axios") - const fs = require("fs-extra") - const path = require("path") - const config = require("../config/config.json") - const api = require("../config/api.json") - - const { channel_id, minecraft_version, modrinth_mods } = config - const { token } = api +const +{ + Client, + Events, + GatewayIntentBits +} = require("discord.js") + +const axios = require("axios") +const fs = require("fs-extra") +const path = require("path") + +const config = require("../config/config.json") +const api = require("../config/api.json") + +const +{ + channel_id, + minecraft_version, + modrinth_mods +} = config + +const +{ + token +} = api + +const cacheFile = path.join(__dirname, "../cache/mod_versions.json") + +const client = new Client +({ + intents: [GatewayIntentBits.Guilds] +}) + +const LoadCache = async () => +{ + try + { + if (await fs.pathExists(cacheFile)) + return JSON.parse(await fs.readFile(cacheFile, "utf8")) + } + catch (err) + { + console.error("[Cache] Failed to read cache:", err) + } + return {} +} - const cacheFile = path.join(__dirname, "../cache/mod_versions.json") - const client = new Client({ intents: [GatewayIntentBits.Guilds] }) +const SaveCache = async cache => +{ + try + { + await fs.ensureDir(path.dirname(cacheFile)) + await fs.writeFile(cacheFile, JSON.stringify(cache, null, 2)) + } + catch (err) + { + console.error("[Cache] Failed to save cache:", err) + } +} - const LoadCache = async () => +const GetModrinthData = async slug => +{ + try { - try - { - if (await fs.pathExists(cacheFile)) - return JSON.parse(await fs.readFile(cacheFile, "utf8")) - } catch (err) - { - console.error("[Cache] Failed to read cache:", err) - } - return {} + const r = await axios.get(`https://api.modrinth.com/v2/project/${slug}/version`) + return r.data } + catch (err) + { + console.error(`[Modrinth] Failed for ${slug}:`, err.message) + return null + } +} + +const CheckMods = async () => +{ + const cache = await LoadCache() + const newCache = { ...cache } + + const updatedNotCompatible = [] + const newlyCompatible = [] + const compatibleUpdated = [] - const SaveCache = async (cache) => + for (const slug of modrinth_mods) { - try - { - await fs.ensureDir(path.dirname(cacheFile)) - await fs.writeFile(cacheFile, JSON.stringify(cache, null, 2)) - } catch (err) - { - console.error("[Cache] Failed to save cache:", err) - } + const versions = await GetModrinthData(slug) + if (!versions) + continue + + const fabric = versions.filter(v => v.loaders.includes("fabric")) + if (!fabric.length) + continue + + const latest = fabric.sort((a, b) => + new Date(b.date_published) - new Date(a.date_published) + )[0] + + const latestId = latest.id + const compatible = latest.game_versions.includes(minecraft_version) + const cachedId = cache[slug] + + if (!cachedId) + newCache[slug] = latestId + + if (latestId === cachedId) + continue + + const previouslyCompatible = fabric.some(v => + v.id === cachedId && v.game_versions.includes(minecraft_version) + ) + + if (!compatible) + updatedNotCompatible.push(slug) + else if (compatible && !previouslyCompatible) + newlyCompatible.push(slug) + else if (compatible && previouslyCompatible) + compatibleUpdated.push(slug) + + newCache[slug] = latestId } - const GetCompatibleModVersion = async (slug, targetMinecraftVersion) => + await SaveCache(newCache) + return { updatedNotCompatible, newlyCompatible, compatibleUpdated } +} + +const SendUpdate = async (channel, updatedNotCompatible, newlyCompatible, compatibleUpdated) => +{ + if (!updatedNotCompatible.length && !newlyCompatible.length && !compatibleUpdated.length) + return + + let msg = `**Modrinth Update Check — ${minecraft_version}**\n\n` + + if (updatedNotCompatible.length) { - try - { - const res = await axios.get(`https://api.modrinth.com/v2/project/${slug}/version`) - const fabricVersions = res.data.filter(v => v.loaders.includes("fabric")) - if (fabricVersions.length === 0) - return null - - const compatible = fabricVersions.find(v => v.game_versions.includes(targetMinecraftVersion)) - const latest = fabricVersions.sort((a, b) => - new Date(b.date_published) - new Date(a.date_published) - )[0] - - return { latest, compatible: compatible || null } - } catch (err) - { - console.error(`[Modrinth] Error fetching ${slug}:`, err.message) - return null - } + msg += `**❗ Updated but NOT compatible:**\n` + for (const s of updatedNotCompatible) + msg += `❗ ${s}\n` + msg += `\n` } - const CheckModUpdates = async () => + if (newlyCompatible.length) { - console.log("[Check] Checking for mod compatibility...") - const cache = await LoadCache() - const newCache = { ...cache } - const compatibleReleased = [] - const waitingUpdate = [] - const newlyCompatible = [] - - for (const slug of modrinth_mods) - { - const modData = await GetCompatibleModVersion(slug, minecraft_version) - if (!modData) continue - - const { latest, compatible } = modData - const latestId = latest.id - const cachedId = cache[slug] - - if (compatible) - { - compatibleReleased.push({ slug }) - newCache[slug] = latestId - - if (!cachedId || cachedId !== latestId) - { - newlyCompatible.push({ slug }) - console.log(`[Update] ${slug} is now compatible with Minecraft ${minecraft_version}`) - } - } else - { - waitingUpdate.push({ slug }) - console.log(`[Check] ${slug} is waiting for a compatible version`) - } - } - - await SaveCache(newCache) - return { compatibleReleased, waitingUpdate, newlyCompatible } + msg += `**🎉 NOW Compatible:**\n` + for (const s of newlyCompatible) + msg += `🎉 ${s}\n` + msg += `\n` } - const SendUpdateMessages = async (channel, compatibleReleased, waitingUpdate, newlyCompatible) => + if (compatibleUpdated.length) { - if (!newlyCompatible.length || !waitingUpdate.length) - { - console.log("[Update]: No mods to report.") - return - } - - let message = `**Mod Compatibility Check — Minecraft ${minecraft_version}**\n\n` + msg += `**🟢 Updated (still compatible):**\n` + for (const s of compatibleUpdated) + msg += `🟢 ${s}\n` + msg += `\n` + } - if (newlyCompatible.length > 0) + await channel.send + ({ + content: msg, + allowedMentions: { - message += `**🎉 Mods Recently Updated:**\n` - for (const { slug } of newlyCompatible) - message += `✅ ${slug}\n` - message += `\n` - } - - const stillCompatible = compatibleReleased.filter( - m => !newlyCompatible.find(n => n.slug === m.slug) - ) - if (stillCompatible.length > 0) - { - message += `**🟢 Mods Compatible:**\n` - for (const { slug } of stillCompatible) - message += `✅ ${slug}\n` - message += `\n` - } - - if (waitingUpdate.length > 0) - { - message += `**⏳ Mods Waiting on Update:**\n` - for (const { slug } of waitingUpdate) - message += `❌ ${slug}\n` - message += `\n` - } - - await channel.send({ content: message, allowedMentions: { parse: [] }, flags: 4 }) - console.log(`[Discord] Sent update summary (${newlyCompatible.length} updated, ${stillCompatible.length} compatible, ${waitingUpdate.length} waiting).`) - } + parse: [] + }, + flags: 4 + }) + + console.log("[Discord] Sent update.") +} + +client.once(Events.ClientReady, async c => +{ + console.log(`[OK] Logged in as ${c.user.tag}`) - client.once(Events.ClientReady, async readyClient => + const channel = await client.channels.fetch(channel_id).catch(() => null) + if (!channel) { - console.log(`[OK] Logged in as ${readyClient.user.tag}`) + console.error("Invalid channel_id:", channel_id) + return + } - const channel = await client.channels.fetch(channel_id).catch(() => null) - if (!channel) { - console.error("❌ Could not find channel ID:", channel_id) - return - } + const + { + updatedNotCompatible, + newlyCompatible, + compatibleUpdated + } = await CheckMods() - const { compatibleReleased, waitingUpdate, newlyCompatible } = await CheckModUpdates() - await SendUpdateMessages(channel, compatibleReleased, waitingUpdate, newlyCompatible) + await SendUpdate(channel, updatedNotCompatible, newlyCompatible, compatibleUpdated) - setInterval(async () => + setInterval(async () => + { + const { - const { compatibleReleased, waitingUpdate, newlyCompatible } = await CheckModUpdates() - await SendUpdateMessages(channel, compatibleReleased, waitingUpdate, newlyCompatible) - }, 60 * 60 * 1000) - }) + updatedNotCompatible, + newlyCompatible, + compatibleUpdated + } = await CheckMods() + + await SendUpdate(channel, updatedNotCompatible, newlyCompatible, compatibleUpdated) + }, 60 * 60 * 1000) +}) - client.login(token) +client.login(token) -- cgit v1.3