From 5a235ad0232e1caeaa769ee7751f38de8e094f5e Mon Sep 17 00:00:00 2001 From: Cynthia Foxwell Date: Thu, 1 May 2025 21:35:19 -0600 Subject: [PATCH] presence: cv2ify --- src/modules/utility/presence.js | 205 +++++++++++++++++++------------- 1 file changed, 122 insertions(+), 83 deletions(-) diff --git a/src/modules/utility/presence.js b/src/modules/utility/presence.js index 3a99145..e8a8eae 100644 --- a/src/modules/utility/presence.js +++ b/src/modules/utility/presence.js @@ -2,13 +2,19 @@ const Command = require("#lib/command.js"); const sharp = require("sharp"); -const {ActivityTypeNames, CDNEndpoints, Games, HangStatusStrings, HANG_STATUS_ICONS} = require("#util/dconstants.js"); +const { + ActivityTypeNames, + CDNEndpoints, + Games, + /*HangStatusStrings, + HANG_STATUS_ICONS*/ +} = require("#util/dconstants.js"); const {Icons} = require("#util/constants.js"); -const {formatUsername} = require("#util/misc.js"); +const {formatUsername, getTopColor} = require("#util/misc.js"); const {lookupUser} = require("#util/selection.js"); const {formatTime} = require("#util/time.js"); -const HangStatusImages = {}; +/*const HangStatusImages = {}; (async () => { for (const key of Object.keys(HANG_STATUS_ICONS)) { const svg = await fetch(HANG_STATUS_ICONS[key]) @@ -16,7 +22,7 @@ const HangStatusImages = {}; .then((b) => Buffer.from(b)); HangStatusImages[key] = await sharp(svg, {density: 2400}).resize(128).toBuffer(); } -})(); +})();*/ const NOWPLAYING_BAR_LENGTH = 32; const NOWPLAYING_BAR_CHAR = "\u2014"; @@ -85,33 +91,64 @@ presence.callback = async function (msg, line) { icons.push(Icons.presence[platform][status]); } - const embeds = []; + const components = []; const files = []; for (const index in target.activities) { const activity = target.activities[index]; if (activity.type == 4) { - const embed = {}; - - if (activity.emoji) { - if (activity.emoji.id) { - const url = CDNEndpoints.EMOJI(activity.emoji.id, activity.emoji.animated); - embed.author = { - url, - icon_url: url, - name: activity.state ?? "\u200b", - }; - } else { - embed.title = `${activity.emoji.name} ${activity.state ?? ""}`; + let label; + if (activity.details) { + switch (activity.details) { + case "listen": + label = "\ud83c\udfb5 On repeat"; + break; + case "watch": + label = "\ud83d\udcfa Watching lately"; + break; + case "play": + label = "\ud83c\udfae Playing lately"; + break; + case "think": + label = "\ud83d\udca1 Shower thought"; + break; + case "love": + label = "\u2764\ufe0f Loving lately"; + break; } - } else { - embed.title = activity.state ?? ""; } - embed.timestamp = new Date(activity.created_at).toISOString(); + let status = ""; + if (label) status = `-# ${label}\n`; + let url; + if (activity.emoji) { + if (activity.emoji.id) { + url = CDNEndpoints.EMOJI(activity.emoji.id, activity.emoji.animated); + } else { + url = `https://jdecked.github.io/twemoji/v/latest/72x72/${[...activity.emoji.name] + .map((char) => char.codePointAt().toString(16)) + .join("-")}.png`; + } + } + status += activity.state ?? "\u200b"; - embeds.push(embed); - } else if (activity.type == 6) { + status += `\n\n-# `; + + const content = { + type: 10, + content: status, + }; + + if (url) { + components.push({ + type: 9, + components: [content], + accessory: {type: 11, media: {url}}, + }); + } else { + components.push(content); + } + /*} else if (activity.type == 6) { const embed = {}; embed.title = "Hang Status"; @@ -135,12 +172,11 @@ presence.callback = async function (msg, line) { embed.timestamp = new Date(activity.created_at).toISOString(); - embeds.push(embed); + embeds.push(embed);*/ } else { - const embed = { - title: `${ActivityTypeNames[activity.type]} **${activity.name}**`, - fields: [], - }; + const comp = []; + comp.push({type: 10, content: `${ActivityTypeNames[activity.type]} **${activity.name}**`}); + const descLines = []; if (activity.type == 2) { if (activity.details) { @@ -207,32 +243,25 @@ presence.callback = async function (msg, line) { } if (activity.assets?.large_text && activity.type != 2) { - embed.fields.push({ - name: "Large Text", - value: activity.assets.large_text, - }); + descLines.push("### Large Text", activity.assets.large_text); } if (activity.assets?.small_text) { - embed.fields.push({ - name: "Small Text", - value: activity.assets.small_text, - }); + descLines.push("### Small Text", activity.assets.small_text); } - if (activity.application_id) { - embed.fields.push({ - name: "Application ID", - value: `\`${activity.application_id}\``, - }); - } + descLines.push( + `\n-# ${activity.application_id ? activity.application_id + " \u2022 " : ""}` + ); - embed.description = descLines.join("\n"); + const content = {type: 10, content: descLines.join("\n")}; + let thumbnail; + const image_links = []; if (activity.assets) { if (activity.assets.large_image != null) { - const image_links = []; - let largeUrl; if (activity.assets.large_image.startsWith("mp:")) { largeUrl = activity.assets.large_image.replace("mp:", "https://media.discordapp.net/"); @@ -242,7 +271,7 @@ presence.callback = async function (msg, line) { largeUrl = CDNEndpoints.APP_ASSET(activity.application_id, activity.assets.large_image); } - image_links.push(`[Large Image](${fixMediaProxyURL(largeUrl)})`); + image_links.push({label: "Large Image", url: fixMediaProxyURL(largeUrl)}); let smallUrl; if (activity.assets.small_image != null) { @@ -254,18 +283,18 @@ presence.callback = async function (msg, line) { smallUrl = CDNEndpoints.APP_ASSET(activity.application_id, activity.assets.small_image); } - image_links.push(`[Small Image](${fixMediaProxyURL(smallUrl)})`); + image_links.push({label: "Small Image", url: fixMediaProxyURL(smallUrl)}); } const largeImage = await fetch(largeUrl) .then((res) => res.arrayBuffer()) .then((b) => Buffer.from(b)); - const presenceImage = sharp(largeImage).resize(60, 60); + const presenceImage = sharp(largeImage).resize(100, 100); if (smallUrl) { const smallImage = await fetch(smallUrl) .then((res) => res.arrayBuffer()) .then((b) => Buffer.from(b)); - const smallImageBuffer = await sharp(smallImage).resize(20, 20).toBuffer(); + const smallImageBuffer = await sharp(smallImage).resize(32, 32).toBuffer(); presenceImage.composite([ { @@ -279,13 +308,7 @@ presence.callback = async function (msg, line) { contents: await presenceImage.toBuffer(), name: `${index}.png`, }); - embed.thumbnail = { - url: `attachment://${index}.png`, - }; - embed.fields.push({ - name: "\u200b", - value: image_links.join("\u3000\u3000"), - }); + thumbnail = `attachment://${index}.png`; } else if (!activity.assets.large_image && activity.assets.small_image != null) { let smallUrl; if (activity.assets.small_image.startsWith("mp:")) { @@ -296,48 +319,64 @@ presence.callback = async function (msg, line) { smallUrl = CDNEndpoints.APP_ASSET(activity.application_id, activity.assets.small_image); } - const smallImage = await fetch(smallUrl) - .then((res) => res.arrayBuffer()) - .then((b) => Buffer.from(b)); - const presenceImage = await sharp(smallImage).resize(40, 40).toBuffer(); - - files.push({ - contents: presenceImage, - name: `${index}.png`, - }); - embed.thumbnail = { - url: `attachment://${index}.png`, - }; - - embed.fields.push({ - name: "\u200b", - value: `[Small Image](${fixMediaProxyURL(smallUrl)})`, - }); + thumbnail = fixMediaProxyURL(smallUrl); + image_links.push({label: "Small Image", url: thumbnail}); } } if (activity.application_id && !activity.assets?.large_image && !activity.assets?.small_image) { const game = Games.find((game) => game.id == activity.application_id); if (game?.icon) { - embed.thumbnail = { - url: `${CDNEndpoints.APP_ICON(game.id, game.icon)}?size=40&keep_aspect_ratio=false`, - }; - embed.fields.push({ - name: "\u200b", - value: `[App Icon](${embed.thumbnail.url.replace("size=40&", "")})`, - }); + thumbnail = `${CDNEndpoints.APP_ICON(game.id, game.icon)}?keep_aspect_ratio=false`; + image_links.push({label: "App Icon", url: thumbnail}); } } - embed.timestamp = new Date(activity.created_at).toISOString(); + if (thumbnail != null) { + comp.push({ + type: 9, + components: [content], + accessory: {type: 11, media: {url: thumbnail}}, + }); + } else { + comp.push(content); + } - embeds.push(embed); + if (image_links.length > 0) { + for (const link of image_links) { + link.type = 2; + link.style = 5; + } + + comp.push({type: 1, components: image_links}); + } + + components.push(comp); } } + const finalComponents = [{type: 10, content: `Presence for **${formatUsername(target)}**: ${icons.join(" ")}`}]; + if (components.length > 0) { + const card = {type: 17, components: [], accent_color: getTopColor(msg, target)}; + + for (const [index, component] of components.entries()) { + if (Array.isArray(component)) { + card.components.push(...component); + } else { + card.components.push(component); + } + + if (index !== components.length - 1) { + card.components.push({type: 14}); + } + } + + finalComponents.push(card); + } + return { - content: `Presence for **${formatUsername(target)}**: ${icons.join(" ")}`, - embeds, + flags: 1 << 15, + components: finalComponents, files, }; } else {