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 anonradio = new Command("anonradio"); anonradio.category = CATEGORY; anonradio.helpText = "aNONradio.net schedule"; anonradio.callback = async function (msg, line) { const now = new Date(); const playing = await fetch("https://anonradio.net/playing").then((res) => res.text() ); const schedule = await fetch("https://anonradio.net/schedule/").then((res) => res.text() ); const icecast = await fetch("http://anonradio.net:8010/status-json.xsl") .then((res) => res.text()) .then((data) => JSON.parse(data.replace(/"title":-,/g, '"title":"-",'))); 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: name.replace(" <- Up NEXT", "")}); } let liveNow = {name: "ident", id: "aNONradio"}; if (parsedLines[0].name.includes("<- Live NOW")) { liveNow = parsedLines.splice(0, 1)[0]; liveNow.name = liveNow.name.replace(" <- Live NOW", ""); } let title = ""; let subtitle = ""; if (playing.includes("listeners with a daily peak of")) { title = `${liveNow.name} (\`${liveNow.id}\`)`; subtitle = playing; } else { const [_, current, peakDay, peakMonth, dj, metadata] = playing.match( /\[(\d+)\/(\d+)\/(\d+)\] \((.+?)\): (.+)/ ); if (metadata == "https://archives.anonradio.net") { title = `${liveNow.name} (\`${dj}\`)`; } else { title = `${metadata} (\`${dj}\`)`; } subtitle = `${current} listening with a daily peak of ${peakDay} and ${peakMonth} peak for the month.`; } let openmicTime = ""; if (liveNow.id == "openmic") { const streamData = icecast.icestats.source.find( (src) => src.listenurl == "http://anonradio.net:8010/openmic" ); if (streamData && streamData.stream_start_iso8601) { const startTime = new Date(streamData.stream_start_iso8601).getTime(); openmicTime = `-*- OpenMIC DJ has been streaming for ${formatTime( Date.now() - startTime )} -*-\n`; } } return { embeds: [ { title: subtitle, author: { name: title, url: "http://anonradio.net:8000/anonradio", }, description: openmicTime + "__Schedule:__", fields: parsedLines.map((line) => ({ inline: true, name: `${line.name} (\`${line.id}\`)`, value: ``, })), }, ], }; }; hf.registerCommand(anonradio); 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);