const Command = require("../lib/command.js"); const events = require("../lib/events.js"); const CATEGORY = "misc"; const FOXWELLS_GUILD_ID = "300436792916836352"; const {tinycolor} = require("@ctrl/tinycolor"); const {pastelize} = require("../lib/utils.js"); const logger = require("../lib/logger.js"); // taken from rot13.com function rot(s, i) { return s.replace(/[a-zA-Z]/g, function (c) { return String.fromCharCode( (c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + i) ? c : c - 26 ); }); } // im making it "hard" to get cause im bored :^) const LIGHTS_URL = "nUE0pUZ6Yl9hqJAfMJSlYaI0p3Ibol5lo2Aepl9fnJqbqN=="; const HEX_REGEX = /^#?([0-9a-fA-F]{1,2})([0-9a-fA-F]{1,2})([0-9a-fA-F]{1,2})$/; let cachedLightsURL; // saving compute time :^) const utsuholights = new Command("utsuholights"); utsuholights.category = CATEGORY; utsuholights.helpText = "Utsuho Lights"; utsuholights.usage = " [brightness]"; utsuholights.callback = async function (msg, line, [hex, bri]) { if (!hex) { return "Hex color required."; } if (!HEX_REGEX.test(hex)) { return "Could not determine hex color."; } const {r, g, b} = tinycolor(hex).toRgb(); if (!cachedLightsURL) { cachedLightsURL = Buffer.from(rot(LIGHTS_URL, 13), "base64").toString(); // Wow! It's That Easy! } const response = await fetch( `${cachedLightsURL}?r=${r}&g=${g}&b=${b}${bri ? `&bri=${bri}` : ""}` ); if (response.status == 200) { return {reaction: "\uD83D\uDC4C"}; } else { return `:warning: An error occurred: \`${await response.text()}\``; } }; hf.registerCommand(utsuholights); const JPEG_HEADER = Buffer.from([ 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, ]); async function fetchPlant() { const res = await fetch("https://nuclear.utsuho.rocks/plant/"); const boundary = res.headers .get("Content-Type") .split(";")[1] .trim() .replace("boundary=", "--"); let buffer = Buffer.alloc(0); let searchForNextBoundary = false; return await new Promise((resolve) => { res.body.on("data", function (data) { if (!searchForNextBoundary) { if (data.toString().startsWith(boundary)) { buffer = Buffer.concat([buffer, data]); searchForNextBoundary = true; } } else if (searchForNextBoundary) { if (data.toString().startsWith(boundary)) { res.body.end(); const length = Number( buffer.toString().match(/Content-Length:.*?(\d+)/)[1] ); const headerOffset = buffer.indexOf(JPEG_HEADER); const data = buffer.slice(headerOffset, headerOffset + length); resolve(data); } else { buffer = Buffer.concat([buffer, data]); } } }); }); } const plant = new Command("plant"); plant.category = CATEGORY; plant.helpText = "Plant cam"; plant.callback = async function () { try { return {file: {file: await fetchPlant(), name: "plant.jpg"}}; } catch (err) { logger.error("hf:cmd:plant", err); return "<:trollhollow:851301241417498704> where plant (Encountered an error getting plant cam)"; } }; hf.registerCommand(plant); /* vinboard */ const VINBOARD_CHANNEL_ID = "770879461871714324"; const VINBOARD_THREAD_ID = "1048462330201124935"; const VINBOARD_WEBHOOK_ID = "1048471543287660665"; hf.database.run( "CREATE TABLE IF NOT EXISTS vinboard (message_id TEXT NOT NULL PRIMARY KEY, count INTEGER NOT NULL, board_id TEXT NOT NULL) WITHOUT ROWID" ); function getBoardEntry(id) { return new Promise((resolve, reject) => { hf.database.get( "SELECT message_id,count,board_id FROM vinboard WHERE message_id = $id", { $id: id, }, (err, row) => { if (err == null) { resolve(row); } else { reject(err); } } ); }); } function setBoardEntry(id, count, board_id) { return new Promise((resolve, reject) => { hf.database.run( "REPLACE INTO vinboard VALUES ($id,$count,$board_id)", { $id: id, $count: count, $board_id: board_id, }, (err) => { if (err == null) { resolve(true); } else { reject(err); } } ); }); } function deleteBoardEntry(id) { return new Promise((resolve, reject) => { hf.database.run( "DELETE FROM vinboard WHERE message_id = $id", { $id: id, }, (err) => { if (err == null) { resolve(true); } else { reject(err); } } ); }); } async function findSuitableImage(msg) { const out = {}; const attachments = [...msg.attachments.values()]; const attachment = attachments[0]; if (attachment) { const url = attachment.url; if (/(jpe?g|png|gif|webp)$/.test(url)) { out.url = url; } else if (/(mp4|webm|mov)$/.test(url)) { out.video = true; out.attachment = true; out.url = "attachment://thumb.jpg"; out.file = await fetch(attachment.proxyURL + "?format=jpeg") .then((res) => res.arrayBuffer()) .then((buf) => Buffer.from(buf)); } } else { for (const embed of msg.embeds) { if (!embed.url) continue; if (embed.url && /(jpe?g|png|gif|webp)$/.test(embed.url)) { out.url = embed.url; } else if (embed.image) { out.url = embed.image.url; break; } else if (embed.video) { out.video = true; out.url = "attachment://thumb.jpg"; out.file = await fetch(embed.video.proxyURL + "?format=jpeg") .then((res) => res.arrayBuffer()) .then((buf) => Buffer.from(buf)); break; } } } return out; } async function createBoardMessage(msg, count, fetchAttachment = true) { const embed = { title: `${count} \u2b50`, color: pastelize(msg.author.username), description: msg.content, fields: [ { name: "Jump Link", value: `[Jump](${msg.jumpLink})`, }, ], timestamp: new Date(msg.timestamp).toISOString(), }; let image; if (fetchAttachment) { image = await findSuitableImage(msg); if (image.url) { if (image.video) { embed.description += `\n(contains video ${ image.attachment ? "attachment" : "embed" })`; } embed.image = { url: image.url, }; } } return { avatarURL: msg.member?.avatarURL ?? msg.author.avatarURL, username: msg.member?.displayName ?? msg.author.username, threadID: VINBOARD_THREAD_ID, embeds: [embed], attachments: image?.file ? [{file: image.file, filename: "thumb.jpg"}] : null, wait: true, }; } let vinboard_webhook; let vin_channel; let board_channel; async function processReaction(_msg, reaction, user) { if (_msg.guildID != FOXWELLS_GUILD_ID) return; if (_msg.channel.id != VINBOARD_CHANNEL_ID) return; if (user.bot) return; if (reaction.name != "\u2b50") return; if (!vin_channel) { vin_channel = hf.bot.guilds .get(FOXWELLS_GUILD_ID) .channels.get(VINBOARD_CHANNEL_ID); } if (!vin_channel) { logger.error("vinboard", "Failed to get channel."); return; } if (!board_channel) { board_channel = hf.bot.guilds .get(FOXWELLS_GUILD_ID) .threads.get(VINBOARD_THREAD_ID); } if (!board_channel) { logger.error("vinboard", "Failed to get thread."); return; } const msg = vin_channel.messages.get(_msg.id) ?? (await vin_channel.getMessage(_msg.id)); if (!vinboard_webhook) { const webhooks = await vin_channel.getWebhooks(); vinboard_webhook = webhooks.find( (webhook) => webhook.id == VINBOARD_WEBHOOK_ID ); } if (!vinboard_webhook) { logger.error("vinboard", "Failed to get webhook."); return; } const reacts = await msg.getReaction("\u2b50"); const trueCount = reacts.filter( (reactor) => reactor.id != msg.author.id ).length; const dbEntry = await getBoardEntry(msg.id); if (dbEntry) { if (trueCount == 0) { logger.verbose("vinboard", `Deleting entry for "${msg.id}"`); if (dbEntry.board_id) { await vinboard_webhook.deleteMessage( dbEntry.board_id, "[Vinboard] Message has 0 reactions now." ); await deleteBoardEntry(msg.id); } } else if (dbEntry.board_id) { const _boardMessage = board_channel.messages.get(dbEntry.board_id) ?? (await board_channel.getMessage(dbEntry.board_id).catch(() => {})); if (_boardMessage) { logger.verbose( "vinboard", `Updating count for "${msg.id}" (${ dbEntry.count ?? 0 } -> ${trueCount})` ); const props = { avatarURL: _boardMessage.author.avatarURL, username: _boardMessage.author.username, threadID: VINBOARD_THREAD_ID, embeds: _boardMessage.embeds, wait: true, }; props.attachments = [..._boardMessage.attachments.values()].map( (attach) => ({id: attach.id}) ); props.embeds[0].title = `${trueCount} \u2b50`; props.embeds[0].color = pastelize(msg.author.username); await hf.bot.editWebhookMessage(vinboard_webhook.id, vinboard_webhook.token, _boardMessage.id, props); await setBoardEntry(msg.id, trueCount, _boardMessage.id); } else { logger.verbose("vinboard", `Creating entry for "${msg.id}"`); const boardMessage = await hf.bot.executeWebhook(vinboard_webhook.id, vinboard_webhook.token, await createBoardMessage(msg, trueCount) ); await setBoardEntry(msg.id, trueCount, boardMessage.id); } } else { logger.verbose("vinboard", `Creating entry for "${msg.id}"`); const boardMessage = await hf.bot.executeWebhook(vinboard_webhook.id, vinboard_webhook.token, await createBoardMessage(msg, trueCount) ); await setBoardEntry(msg.id, trueCount, boardMessage.id); } } else { logger.verbose("vinboard", `Creating entry for "${msg.id}"`); const boardMessage = await hf.bot.executeWebhook(vinboard_webhook.id, vinboard_webhook.token, await createBoardMessage(msg, trueCount) ); await setBoardEntry(msg.id, trueCount, boardMessage.id); } } events.add("messageReactionAdd", "vinboard", processReaction); events.add("messageReactionRemove", "vinboard", processReaction);