From 7231dea94580308ae7b29e41928790ba26966137 Mon Sep 17 00:00:00 2001 From: Cynthia Foxwell Date: Tue, 2 Aug 2022 22:23:46 -0600 Subject: [PATCH] update some deps --- package.json | 2 +- pnpm-lock.yaml | 40 +- src/modules/misc.js | 920 ++++++++++++++++++++++---------------------- 3 files changed, 481 insertions(+), 481 deletions(-) diff --git a/package.json b/package.json index cb5e62d..492130a 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "node-ffprobe": "^3.0.0", "sharp": "^0.28.3", "sqlite3": "^5.0.2", - "ytdl-core": "^4.9.1" + "ytdl-core": "4.11.0" }, "devDependencies": { "eslint": "^7.26.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b970625..755f715 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,12 +13,12 @@ specifiers: prettier: ^2.3.0 sharp: ^0.28.3 sqlite3: ^5.0.2 - ytdl-core: ^4.9.1 + ytdl-core: 4.11.0 dependencies: '@ctrl/tinycolor': 3.4.1 dumpy: github.com/Cynosphere/dumpy.js/5fc22353cdcb97084bab572266390e780d9f7a7b - eris: github.com/abalabahaha/eris/bd58677d91b532dd06227e73824b2cb40de9e816 + eris: github.com/abalabahaha/eris/4ea56e45ffe68e95d89d7f3edcc181097f4f9f8d google-images: 2.1.0 jimp: 0.16.1 murmurhash: 2.0.0 @@ -26,7 +26,7 @@ dependencies: node-ffprobe: 3.0.0 sharp: 0.28.3 sqlite3: 5.0.2 - ytdl-core: 4.9.1 + ytdl-core: 4.11.0 devDependencies: eslint: 7.26.0 @@ -695,7 +695,7 @@ packages: dev: true /color-name/1.1.3: - resolution: {integrity: sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=} + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} /color-name/1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -1442,11 +1442,11 @@ packages: dependencies: yallist: 4.0.0 - /m3u8stream/0.8.4: - resolution: {integrity: sha512-sco80Db+30RvcaIOndenX6E6oQNgTiBKeJbFPc+yDXwPQIkryfboEbCvXPlBRq3mQTCVPQO93TDVlfRwqpD35w==} - engines: {node: '>=10'} + /m3u8stream/0.8.6: + resolution: {integrity: sha512-LZj8kIVf9KCphiHmH7sbFQTVe4tOemb202fWwvJwR9W5ENW/1hxJN6ksAWGhQgSBSa3jyWhnjKU1Fw1GaOdbyA==} + engines: {node: '>=12'} dependencies: - miniget: 4.2.1 + miniget: 4.2.2 sax: 1.2.4 dev: false @@ -1481,9 +1481,9 @@ packages: dom-walk: 0.1.2 dev: false - /miniget/4.2.1: - resolution: {integrity: sha512-O/DduzDR6f+oDtVype9S/Qu5hhnx73EDYGyZKwU/qN82lehFZdfhoa4DT51SpsO+8epYrB3gcRmws56ROfTIoQ==} - engines: {node: '>=10'} + /miniget/4.2.2: + resolution: {integrity: sha512-a7voNL1N5lDMxvTMExOkg+Fq89jM2vY8pAi9ZEWzZtfNmdfP6RXkvUtFnCAXoCv2T9k1v/fUJVaAEuepGcvLYA==} + engines: {node: '>=12'} dev: false /minimatch/3.0.4: @@ -2231,7 +2231,7 @@ packages: dev: false /tweetnacl/0.14.5: - resolution: {integrity: sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=} + resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} dev: false optional: true @@ -2387,12 +2387,12 @@ packages: /yallist/4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - /ytdl-core/4.9.1: - resolution: {integrity: sha512-6Jbp5RDhUEozlaJQAR+l8oV8AHsx3WUXxSyPxzE6wOIAaLql7Hjiy0ZM58wZoyj1YEenlEPjEqcJIjKYKxvHtQ==} - engines: {node: '>=10'} + /ytdl-core/4.11.0: + resolution: {integrity: sha512-Q3hCLiUA9AOGQXzPvno14GN+HgF9wsO1ZBHlj0COTcyxjIyFpWvMfii0UC4/cAbVaIjEdbWB71GdcGuc4J1Lmw==} + engines: {node: '>=12'} dependencies: - m3u8stream: 0.8.4 - miniget: 4.2.1 + m3u8stream: 0.8.6 + miniget: 4.2.2 sax: 1.2.4 dev: false @@ -2407,10 +2407,10 @@ packages: node-fetch: 2.6.1 dev: false - github.com/abalabahaha/eris/bd58677d91b532dd06227e73824b2cb40de9e816: - resolution: {tarball: https://codeload.github.com/abalabahaha/eris/tar.gz/bd58677d91b532dd06227e73824b2cb40de9e816} + github.com/abalabahaha/eris/4ea56e45ffe68e95d89d7f3edcc181097f4f9f8d: + resolution: {tarball: https://codeload.github.com/abalabahaha/eris/tar.gz/4ea56e45ffe68e95d89d7f3edcc181097f4f9f8d} name: eris - version: 0.17.1-dev + version: 0.17.2-dev engines: {node: '>=10.4.0'} dependencies: ws: 8.5.0 diff --git a/src/modules/misc.js b/src/modules/misc.js index f775ff9..0175f70 100644 --- a/src/modules/misc.js +++ b/src/modules/misc.js @@ -1,460 +1,460 @@ -const Command = require("../lib/command.js"); -const CATEGORY = "misc"; - -const fetch = require("node-fetch"); -const { - hastebin, - safeString, - parseHtmlEntities, - formatTime, -} = require("../lib/utils.js"); -const GoogleImages = require("google-images"); - -const imagesClient = new GoogleImages(hf.apikeys.gimg, hf.apikeys.google); - -const yt = new Command("youtube"); -yt.addAlias("yt"); -yt.category = CATEGORY; -yt.helpText = "Search YouTube"; -yt.usage = "[search term]"; -yt.callback = async function (msg, line) { - if (!line) return "Arguments are required."; - - const req = await fetch( - `https://www.googleapis.com/youtube/v3/search?key=${ - hf.apikeys.google - }&maxResults=5&part=snippet&type=video&q=${encodeURIComponent(line)}` - ).then((x) => x.json()); - - const topVid = req.items[0]; - - let out = `**${safeString( - parseHtmlEntities(topVid.snippet.title) - )}** | \`${safeString( - parseHtmlEntities(topVid.snippet.channelTitle) - )}\`\nhttps://youtu.be/${topVid.id.videoId}\n\n**__See Also:__**\n`; - - for (let i = 1; i < req.items.length; i++) { - const vid = req.items[i]; - out += `- **${safeString( - parseHtmlEntities(vid.snippet.title) - )}** | By: \`${safeString( - parseHtmlEntities(vid.snippet.channelTitle) - )}\` | \n`; - } - - return out; -}; -hf.registerCommand(yt); - -const fyt = new Command("fyt"); -fyt.category = CATEGORY; -fyt.helpText = "Search YouTube and take the first result."; -fyt.usage = "[search term]"; -fyt.callback = async function (msg, line) { - if (!line) return "Arguments are required."; - - const req = await fetch( - `https://www.googleapis.com/youtube/v3/search?key=${ - hf.apikeys.google - }&maxResults=2&part=snippet&type=video&q=${encodeURIComponent(line)}` - ).then((x) => x.json()); - - const vid = req.items[0]; - - return `**${safeString( - parseHtmlEntities(vid.snippet.title) - )}** | \`${safeString( - parseHtmlEntities(vid.snippet.channelTitle) - )}\`\nhttps://youtu.be/${vid.id.videoId}`; -}; -hf.registerCommand(fyt); - -const WA_NO_ANSWER = "<:ms_cross:503341994974773250> No answer."; - -const wolfram = new Command("wolfram"); -wolfram.category = CATEGORY; -wolfram.helpText = "Wolfram Alpha"; -wolfram.usage = "<-v> [query]"; -wolfram.addAlias("wa"); -wolfram.callback = async function (msg, line) { - let verbose = false; - - if (line.includes("-v")) { - line = line.replace("-v", "").trim(); - verbose = true; - } - - const req = await fetch( - `http://api.wolframalpha.com/v2/query?input=${encodeURIComponent( - line - )}&appid=LH2K8H-T3QKETAGT3&output=json` - ).then((x) => x.json()); - - const data = req.queryresult.pods; - - if (!data) return WA_NO_ANSWER; - - // fake no answer - if (data[0].subpods[0].plaintext.includes("geoIP")) return WA_NO_ANSWER; - - if (verbose) { - const embed = { - title: `Result for: \`${safeString(line)}\``, - fields: [], - footer: { - icon_url: "http://www.wolframalpha.com/share.png", - text: "Powered by Wolfram Alpha", - }, - image: { - url: data[1].subpods[0].img.src, - }, - }; - - const extra = data.slice(1, 6); - for (const x in extra) { - embed.fields.push({ - name: extra[x].title, - value: `[${ - extra[x].subpods[0].plaintext.length > 0 - ? extra[x].subpods[0].plaintext - : "" - }](${extra[x].subpods[0].img.src})`, - inline: true, - }); - } - - return {embed}; - } else { - let image; - - if (data[1].subpods[0].img.src) - try { - const res = await fetch(data[1].subpods[0].img.src); - if (res) { - const imgData = await res.arrayBuffer(); - image = Buffer.from(imgData); - } - } catch { - // - } - - let string = ""; - if (data[1].subpods[0].plaintext.length > 0) - string = safeString(data[1].subpods[0].plaintext); - - if (string.length > 2000 - (6 + safeString(line).length)) - string = "Output too long: " + (await hastebin(string)); - - return { - content: `\`${safeString(line)}\` -> ${string.length > 0 ? string : ""}`, - file: image && { - file: image, - name: "wolfram_output.gif", - }, - }; - } -}; -hf.registerCommand(wolfram); - -const gimg = new Command("gimg"); -gimg.category = CATEGORY; -gimg.helpText = "Search Google Images"; -gimg.usage = "[query]"; -gimg.addAlias("img"); -gimg.callback = async function (msg, line) { - if (!line) return "No arguments given."; - - const images = await imagesClient.search(line, { - safe: - msg.channel.nsfw && !msg.channel?.topic.includes("[no_nsfw]") - ? "off" - : "high", - }); - - const index = Math.floor(Math.random() * images.length); - const image = images[index]; - - return { - embeds: [ - { - title: image.description, - url: image.parentPage, - image: { - url: image.url, - }, - footer: { - text: `Image ${index}/${images.length}. Rerun to get a different image.`, - }, - }, - ], - }; -}; -hf.registerCommand(gimg); - -const fimg = new Command("fimg"); -fimg.category = CATEGORY; -fimg.helpText = "Send first result from Google Images"; -fimg.usage = "[query]"; -fimg.callback = async function (msg, line) { - if (!line) return "No arguments given."; - - const images = await imagesClient.search(line, { - safe: - msg.channel.nsfw && !msg.channel?.topic.includes("[no_nsfw]") - ? "off" - : "high", - }); - - const image = images[0]; - - return { - embeds: [ - { - title: image.description, - url: image.parentPage, - image: { - url: image.url, - }, - }, - ], - }; -}; -hf.registerCommand(fimg); - -const poll = new Command("poll"); -poll.category = CATEGORY; -poll.helpText = "Start a poll"; -poll.usage = "[topic] [option 1] [option 2] [...option 3-10]"; -poll.callback = async function (msg, line, topic, ...options) { - if (!line || !topic) - return 'Usage: hf!poll "topic" "option 1" "option 2" "...options 3-10"'; - - const arrOptions = [...options].slice(0, 10); - if (arrOptions.length < 2) return "A minimum of two options are required."; - - const reactions = []; - let displayString = `**${msg.author.username}#${msg.author.discriminator}** has started a poll:\n**__${topic}__**\n`; - for (let i = 0; i < arrOptions.length; i++) { - displayString += - (i === 9 ? "\ud83d\udd1f" : `${i + 1}\u20e3`) + - ": " + - arrOptions[i] + - "\n"; - reactions[i] = i === 9 ? "\ud83d\udd1f" : `${i + 1}\u20e3`; - } - - return { - content: displayString, - addReactions: reactions, - }; -}; -hf.registerCommand(poll); - -const vote = new Command("vote"); -vote.category = CATEGORY; -vote.helpText = "Start a yes/no vote"; -vote.usage = "[topic]"; -vote.callback = async function (msg, line) { - if (!line) return "No topic given."; - - return { - content: `**${msg.author.username}#${msg.author.discriminator}** has started a vote:\n**__${line}__**\n<:ms_tick:503341995348066313>: Yes\n<:ms_cross:503341994974773250>: No`, - addReactions: [ - ":ms_tick:503341995348066313", - ":ms_cross:503341994974773250", - ], - }; -}; -hf.registerCommand(vote); - -const DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; -const arsched = new Command("arsched"); -arsched.category = CATEGORY; -arsched.helpText = "aNONradio.net schedule"; -arsched.addAlias("anonradio"); -arsched.callback = async function (msg, line) { - const now = new Date(); - - const schedule = await fetch("https://anonradio.net/schedule/").then((res) => - res.text() - ); - - let lines = schedule.split("\n"); - lines = lines.slice(4, lines.length - 2); - - const parsedLines = []; - - for (const line of lines) { - const [_, time, id, name] = line.match(/^(.{3,4} .{4})\s+(.+?) {2}(.+?)$/); - - const tmp = time.split(" "); - const day = tmp[0]; - let hour = tmp[1]; - const currentDay = now.getUTCDay(); - const targetDay = DAYS.indexOf(day); - const delta = (targetDay + 7 - currentDay) % 7; - - let currentYear = now.getUTCFullYear(); - const currentMonth = now.getUTCMonth() + 1; - const currentDateDay = now.getUTCDate(); - let targetMonth = currentMonth; - const lastDay = new Date(currentYear, currentMonth, 0).getDate(); - let targetDateDay = currentDateDay + delta; - if (targetDateDay > lastDay) { - targetMonth = currentMonth === 12 ? 1 : currentMonth + 1; - targetDateDay = 1; - if (currentMonth === 12) currentYear++; - } - - hour = hour.slice(0, 2) + ":" + hour.slice(-2); - - const timestamp = - Date.parse( - `${DAYS[targetDay]}, ${currentYear}-${targetMonth}-${targetDateDay} ${hour} UTC` - ) / 1000; - - parsedLines.push({timestamp, id, name}); - } - - const liveNow = parsedLines.splice(0, 1)[0]; - liveNow.name = liveNow.name.replace(" <- Live NOW", ""); - - return { - embeds: [ - { - title: "Click to listen", - url: "http://anonradio.net:8000/anonradio", - author: { - name: `LIVE NOW: ${liveNow.name} (\`${liveNow.id}\`)`, - }, - fields: parsedLines.map((line) => ({ - inline: true, - name: `${line.name} (\`${line.id}\`)`, - value: ``, - })), - }, - ], - }; -}; -hf.registerCommand(arsched); - -const REGEX_IPV4 = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)(\.(?!$)|$)){4}$/; -const shodan = new Command("shodan"); -shodan.category = CATEGORY; -shodan.helpText = "Look up an IP on Shodan InternetDB"; -shodan.callback = async function (msg, line) { - if (!line || line == "") return "Arguments required."; - if (!REGEX_IPV4.test(line)) return "Invalid IP address."; - - const data = await fetch("https://internetdb.shodan.io/" + line).then((res) => - res.json() - ); - - if (data.detail) return data.detail; - - return { - embed: { - title: `Results for \`${data.ip}\``, - fields: [ - { - name: "Hostnames", - value: - data.hostnames.length > 0 - ? data.hostnames.map((str) => `\`${str}\``).join("\n") - : "None", - inline: true, - }, - { - name: "Open ports", - value: data.ports.length > 0 ? data.ports.join(", ") : "None", - inline: true, - }, - { - name: "Tags", - value: - data.tags.length > 0 - ? data.tags.map((str) => `\`${str}\``).join(", ") - : "None", - inline: true, - }, - { - name: "CPEs", - value: - data.cpes.length > 0 - ? data.cpes.map((str) => `\`${str}\``).join("\n") - : "None", - inline: true, - }, - { - name: "Vulnerabilities", - value: - data.vulns.length > 0 - ? data.vulns.map((str) => `\`${str}\``).join("\n") - : "None", - inline: true, - }, - ], - }, - }; -}; -hf.registerCommand(shodan); - -const GENERATE_HEADERS = { - Accept: "application/json", - "Content-Type": "application/json", -}; -const generate = new Command("generate"); -generate.category = CATEGORY; -generate.helpText = "Generate images from prompt via craiyon"; -generate.callback = async function (msg, line) { - if (!line || line.length === 0) return "Arguments required."; - msg.channel.sendTyping(); - - const start = Date.now(); - let retries = 0; - - let request = await fetch("https://backend.craiyon.com/generate", { - method: "POST", - headers: GENERATE_HEADERS, - body: JSON.stringify({prompt: line}), - }); - while (request.status !== 200) { - request = await fetch("https://backend.craiyon.com/generate", { - method: "POST", - headers: GENERATE_HEADERS, - body: JSON.stringify({prompt: line}), - }); - retries++; - } - - const data = await request.json(); - const images = data.images - .map((img) => Buffer.from(img, "base64")) - .map((img, index) => ({file: img, name: `${index}.jpg`})); - - const title = `Responses for "${safeString(line)}"`; - - const out = { - content: `Generated in ${formatTime(Date.now() - start)}${ - retries > 0 ? " with " + retries + " retries" : "" - }`, - embeds: [], - file: images, - }; - - let splitIndex = 0; - for (const index in images) { - if (index % 3 == 0) splitIndex++; - out.embeds.push({ - title, - url: "https://www.craiyon.com/?" + splitIndex, - image: { - url: `attachment://${index}.jpg`, - }, - }); - } - - return out; -}; -hf.registerCommand(generate); +const Command = require("../lib/command.js"); +const CATEGORY = "misc"; + +const fetch = require("node-fetch"); +const { + hastebin, + safeString, + parseHtmlEntities, + formatTime, +} = require("../lib/utils.js"); +const GoogleImages = require("google-images"); + +const imagesClient = new GoogleImages(hf.apikeys.gimg, hf.apikeys.google); + +const yt = new Command("youtube"); +yt.addAlias("yt"); +yt.category = CATEGORY; +yt.helpText = "Search YouTube"; +yt.usage = "[search term]"; +yt.callback = async function (msg, line) { + if (!line) return "Arguments are required."; + + const req = await fetch( + `https://www.googleapis.com/youtube/v3/search?key=${ + hf.apikeys.google + }&maxResults=5&part=snippet&type=video&q=${encodeURIComponent(line)}` + ).then((x) => x.json()); + + const topVid = req.items[0]; + + let out = `**${safeString( + parseHtmlEntities(topVid.snippet.title) + )}** | \`${safeString( + parseHtmlEntities(topVid.snippet.channelTitle) + )}\`\nhttps://youtu.be/${topVid.id.videoId}\n\n**__See Also:__**\n`; + + for (let i = 1; i < req.items.length; i++) { + const vid = req.items[i]; + out += `- **${safeString( + parseHtmlEntities(vid.snippet.title) + )}** | By: \`${safeString( + parseHtmlEntities(vid.snippet.channelTitle) + )}\` | \n`; + } + + return out; +}; +hf.registerCommand(yt); + +const fyt = new Command("fyt"); +fyt.category = CATEGORY; +fyt.helpText = "Search YouTube and take the first result."; +fyt.usage = "[search term]"; +fyt.callback = async function (msg, line) { + if (!line) return "Arguments are required."; + + const req = await fetch( + `https://www.googleapis.com/youtube/v3/search?key=${ + hf.apikeys.google + }&maxResults=2&part=snippet&type=video&q=${encodeURIComponent(line)}` + ).then((x) => x.json()); + + const vid = req.items[0]; + + return `**${safeString( + parseHtmlEntities(vid.snippet.title) + )}** | \`${safeString( + parseHtmlEntities(vid.snippet.channelTitle) + )}\`\nhttps://youtu.be/${vid.id.videoId}`; +}; +hf.registerCommand(fyt); + +const WA_NO_ANSWER = "<:ms_cross:503341994974773250> No answer."; + +const wolfram = new Command("wolfram"); +wolfram.category = CATEGORY; +wolfram.helpText = "Wolfram Alpha"; +wolfram.usage = "<-v> [query]"; +wolfram.addAlias("wa"); +wolfram.callback = async function (msg, line) { + let verbose = false; + + if (line.includes("-v")) { + line = line.replace("-v", "").trim(); + verbose = true; + } + + const req = await fetch( + `http://api.wolframalpha.com/v2/query?input=${encodeURIComponent( + line + )}&appid=LH2K8H-T3QKETAGT3&output=json` + ).then((x) => x.json()); + + const data = req.queryresult.pods; + + if (!data) return WA_NO_ANSWER; + + // fake no answer + if (data[0].subpods[0].plaintext.includes("geoIP")) return WA_NO_ANSWER; + + if (verbose) { + const embed = { + title: `Result for: \`${safeString(line)}\``, + fields: [], + footer: { + icon_url: "http://www.wolframalpha.com/share.png", + text: "Powered by Wolfram Alpha", + }, + image: { + url: data[1].subpods[0].img.src, + }, + }; + + const extra = data.slice(1, 6); + for (const x in extra) { + embed.fields.push({ + name: extra[x].title, + value: `[${ + extra[x].subpods[0].plaintext.length > 0 + ? extra[x].subpods[0].plaintext + : "" + }](${extra[x].subpods[0].img.src})`, + inline: true, + }); + } + + return {embed}; + } else { + let image; + + if (data[1].subpods[0].img.src) + try { + const res = await fetch(data[1].subpods[0].img.src); + if (res) { + const imgData = await res.arrayBuffer(); + image = Buffer.from(imgData); + } + } catch { + // + } + + let string = ""; + if (data[1].subpods[0].plaintext.length > 0) + string = safeString(data[1].subpods[0].plaintext); + + if (string.length > 2000 - (6 + safeString(line).length)) + string = "Output too long: " + (await hastebin(string)); + + return { + content: `\`${safeString(line)}\` -> ${string.length > 0 ? string : ""}`, + file: image && { + file: image, + name: "wolfram_output.gif", + }, + }; + } +}; +hf.registerCommand(wolfram); + +const gimg = new Command("gimg"); +gimg.category = CATEGORY; +gimg.helpText = "Search Google Images"; +gimg.usage = "[query]"; +gimg.addAlias("img"); +gimg.callback = async function (msg, line) { + if (!line) return "No arguments given."; + + const images = await imagesClient.search(line, { + safe: + msg.channel.nsfw && !msg.channel?.topic.includes("[no_nsfw]") + ? "off" + : "high", + }); + + const index = Math.floor(Math.random() * images.length); + const image = images[index]; + + return { + embeds: [ + { + title: image.description, + url: image.parentPage, + image: { + url: image.url, + }, + footer: { + text: `Image ${index}/${images.length}. Rerun to get a different image.`, + }, + }, + ], + }; +}; +hf.registerCommand(gimg); + +const fimg = new Command("fimg"); +fimg.category = CATEGORY; +fimg.helpText = "Send first result from Google Images"; +fimg.usage = "[query]"; +fimg.callback = async function (msg, line) { + if (!line) return "No arguments given."; + + const images = await imagesClient.search(line, { + safe: + msg.channel.nsfw && !msg.channel?.topic.includes("[no_nsfw]") + ? "off" + : "high", + }); + + const image = images[0]; + + return { + embeds: [ + { + title: image.description, + url: image.parentPage, + image: { + url: image.url, + }, + }, + ], + }; +}; +hf.registerCommand(fimg); + +const poll = new Command("poll"); +poll.category = CATEGORY; +poll.helpText = "Start a poll"; +poll.usage = "[topic] [option 1] [option 2] [...option 3-10]"; +poll.callback = async function (msg, line, topic, ...options) { + if (!line || !topic) + return 'Usage: hf!poll "topic" "option 1" "option 2" "...options 3-10"'; + + const arrOptions = [...options].slice(0, 10); + if (arrOptions.length < 2) return "A minimum of two options are required."; + + const reactions = []; + let displayString = `**${msg.author.username}#${msg.author.discriminator}** has started a poll:\n**__${topic}__**\n`; + for (let i = 0; i < arrOptions.length; i++) { + displayString += + (i === 9 ? "\ud83d\udd1f" : `${i + 1}\u20e3`) + + ": " + + arrOptions[i] + + "\n"; + reactions[i] = i === 9 ? "\ud83d\udd1f" : `${i + 1}\u20e3`; + } + + return { + content: displayString, + addReactions: reactions, + }; +}; +hf.registerCommand(poll); + +const vote = new Command("vote"); +vote.category = CATEGORY; +vote.helpText = "Start a yes/no vote"; +vote.usage = "[topic]"; +vote.callback = async function (msg, line) { + if (!line) return "No topic given."; + + return { + content: `**${msg.author.username}#${msg.author.discriminator}** has started a vote:\n**__${line}__**\n<:ms_tick:503341995348066313>: Yes\n<:ms_cross:503341994974773250>: No`, + addReactions: [ + ":ms_tick:503341995348066313", + ":ms_cross:503341994974773250", + ], + }; +}; +hf.registerCommand(vote); + +const DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; +const arsched = new Command("arsched"); +arsched.category = CATEGORY; +arsched.helpText = "aNONradio.net schedule"; +arsched.addAlias("anonradio"); +arsched.callback = async function (msg, line) { + const now = new Date(); + + const schedule = await fetch("https://anonradio.net/schedule/").then((res) => + res.text() + ); + + let lines = schedule.split("\n"); + lines = lines.slice(4, lines.length - 2); + + const parsedLines = []; + + for (const line of lines) { + const [_, time, id, name] = line.match(/^(.{3,4} .{4})\s+(.+?) {2}(.+?)$/); + + const tmp = time.split(" "); + const day = tmp[0]; + let hour = tmp[1]; + const currentDay = now.getUTCDay(); + const targetDay = DAYS.indexOf(day); + const delta = (targetDay + 7 - currentDay) % 7; + + let currentYear = now.getUTCFullYear(); + const currentMonth = now.getUTCMonth() + 1; + const currentDateDay = now.getUTCDate(); + let targetMonth = currentMonth; + const lastDay = new Date(currentYear, currentMonth, 0).getDate(); + let targetDateDay = currentDateDay + delta; + if (targetDateDay > lastDay) { + targetMonth = currentMonth === 12 ? 1 : currentMonth + 1; + targetDateDay = 1; + if (currentMonth === 12) currentYear++; + } + + hour = hour.slice(0, 2) + ":" + hour.slice(-2); + + const timestamp = + Date.parse( + `${DAYS[targetDay]}, ${currentYear}-${targetMonth}-${targetDateDay} ${hour} UTC` + ) / 1000; + + parsedLines.push({timestamp, id, name}); + } + + const liveNow = parsedLines.splice(0, 1)[0]; + liveNow.name = liveNow.name.replace(" <- Live NOW", ""); + + return { + embeds: [ + { + title: "Click to listen", + url: "http://anonradio.net:8000/anonradio", + author: { + name: `LIVE NOW: ${liveNow.name} (\`${liveNow.id}\`)`, + }, + fields: parsedLines.map((line) => ({ + inline: true, + name: `${line.name} (\`${line.id}\`)`, + value: ``, + })), + }, + ], + }; +}; +hf.registerCommand(arsched); + +const REGEX_IPV4 = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)(\.(?!$)|$)){4}$/; +const shodan = new Command("shodan"); +shodan.category = CATEGORY; +shodan.helpText = "Look up an IP on Shodan InternetDB"; +shodan.callback = async function (msg, line) { + if (!line || line == "") return "Arguments required."; + if (!REGEX_IPV4.test(line)) return "Invalid IP address."; + + const data = await fetch("https://internetdb.shodan.io/" + line).then((res) => + res.json() + ); + + if (data.detail) return data.detail; + + return { + embed: { + title: `Results for \`${data.ip}\``, + fields: [ + { + name: "Hostnames", + value: + data.hostnames.length > 0 + ? data.hostnames.map((str) => `\`${str}\``).join("\n") + : "None", + inline: true, + }, + { + name: "Open ports", + value: data.ports.length > 0 ? data.ports.join(", ") : "None", + inline: true, + }, + { + name: "Tags", + value: + data.tags.length > 0 + ? data.tags.map((str) => `\`${str}\``).join(", ") + : "None", + inline: true, + }, + { + name: "CPEs", + value: + data.cpes.length > 0 + ? data.cpes.map((str) => `\`${str}\``).join("\n") + : "None", + inline: true, + }, + { + name: "Vulnerabilities", + value: + data.vulns.length > 0 + ? data.vulns.map((str) => `\`${str}\``).join("\n") + : "None", + inline: true, + }, + ], + }, + }; +}; +hf.registerCommand(shodan); + +const GENERATE_HEADERS = { + Accept: "application/json", + "Content-Type": "application/json", +}; +const generate = new Command("generate"); +generate.category = CATEGORY; +generate.helpText = "Generate images from prompt via craiyon"; +generate.callback = async function (msg, line) { + if (!line || line.length === 0) return "Arguments required."; + msg.channel.sendTyping(); + + const start = Date.now(); + let retries = 0; + + let request = await fetch("https://backend.craiyon.com/generate", { + method: "POST", + headers: GENERATE_HEADERS, + body: JSON.stringify({prompt: line}), + }); + while (request.status !== 200) { + request = await fetch("https://backend.craiyon.com/generate", { + method: "POST", + headers: GENERATE_HEADERS, + body: JSON.stringify({prompt: line}), + }); + retries++; + } + + const data = await request.json(); + const images = data.images + .map((img) => Buffer.from(img, "base64")) + .map((img, index) => ({file: img, name: `${index}.jpg`})); + + const title = `Responses for "${safeString(line)}"`; + + const out = { + content: `Generated in ${formatTime(Date.now() - start)}${ + retries > 0 ? " with " + retries + " retries" : "" + }`, + embeds: [], + file: images, + }; + + let splitIndex = 0; + for (const index in images) { + if (index % 3 == 0) splitIndex++; + out.embeds.push({ + title, + url: "https://www.craiyon.com/?" + splitIndex, + image: { + url: `attachment://${index}.jpg`, + }, + }); + } + + return out; +}; +hf.registerCommand(generate);