fedimbed: attempt to components v2 fedi posts

This commit is contained in:
Cynthia Foxwell 2025-04-18 18:10:33 -06:00
parent 15f709ed13
commit fd98ba3667
Signed by: Cynosphere
SSH key fingerprint: SHA256:H3SM8ufP/uxqLwKSH7xY89TDnbR9uOHzjLoBr0tlajk

View file

@ -1,5 +1,3 @@
const {Message} = require("@projectdysnomia/dysnomia");
const fs = require("node:fs"); const fs = require("node:fs");
const httpSignature = require("@peertube/http-signature"); const httpSignature = require("@peertube/http-signature");
const {XMLParser} = require("fast-xml-parser"); const {XMLParser} = require("fast-xml-parser");
@ -11,7 +9,6 @@ const InteractionCommand = require("#lib/interactionCommand.js");
const {Icons} = require("#util/constants.js"); const {Icons} = require("#util/constants.js");
const {MessageFlags, ApplicationCommandOptionTypes, Permissions} = require("#util/dconstants.js"); const {MessageFlags, ApplicationCommandOptionTypes, Permissions} = require("#util/dconstants.js");
const {getUploadLimit} = require("#util/misc.js");
const {htmlToMarkdown} = require("#util/html.js"); const {htmlToMarkdown} = require("#util/html.js");
const FRIENDLY_USERAGENT = const FRIENDLY_USERAGENT =
@ -715,7 +712,7 @@ async function bluesky(msg, url, spoiler = false) {
return { return {
response: { response: {
flags: 1 << 15, flags: 1 << 15,
components: [warnings.length > 0 ? warningText : false, container].filter((x) => !!x), components: [warnings.length > 0 && warningText, container].filter((x) => !!x),
allowedMentions: { allowedMentions: {
repliedUser: false, repliedUser: false,
}, },
@ -910,18 +907,20 @@ async function getStatsAS(post) {
} }
const stats = []; const stats = [];
if (replyCount > 0) stats.push(`\u21a9 ${statsFormatter.format(replyCount)}`); if (replyCount > 0) stats.push(`${Icons.fedimbed.reply} ${statsFormatter.format(replyCount)}`);
if (post.shares?.totalItems ?? 0 > 0) stats.push(`\ud83d\udd01 ${statsFormatter.format(post.shares.totalItems)}`); if (post.shares?.totalItems ?? 0 > 0)
if (post.likes?.totalItems ?? 0 > 0) stats.push(`\u2665 ${statsFormatter.format(post.likes.totalItems)}`); stats.push(`${Icons.fedimbed.repost} ${statsFormatter.format(post.shares.totalItems)}`);
if (post.likes?.totalItems ?? 0 > 0)
stats.push(`${Icons.fedimbed.like} ${statsFormatter.format(post.likes.totalItems)}`);
return stats.join("\u3000"); return stats.join("\u3000");
} }
function getStatsMasto(post) { function getStatsMasto(post) {
const stats = []; const stats = [];
if (post.replies_count > 0) stats.push(`\u21a9 ${statsFormatter.format(post.replies_count)}`); if (post.replies_count > 0) stats.push(`${Icons.fedimbed.reply} ${statsFormatter.format(post.replies_count)}`);
if (post.reblogs_count > 0) stats.push(`\ud83d\udd01 ${statsFormatter.format(post.reblogs_count)}`); if (post.reblogs_count > 0) stats.push(`${Icons.fedimbed.repost} ${statsFormatter.format(post.reblogs_count)}`);
if (post.favourites_count > 0) stats.push(`\u2665 ${statsFormatter.format(post.favourites_count)}`); if (post.favourites_count > 0) stats.push(`${Icons.fedimbed.like} ${statsFormatter.format(post.favourites_count)}`);
return stats.join("\u3000"); return stats.join("\u3000");
} }
@ -1061,58 +1060,23 @@ async function processUrl(msg, url, spoiler = false, command = false) {
const attachments = postData.media_attachments ?? postData.files; const attachments = postData.media_attachments ?? postData.files;
if (attachments) { if (attachments) {
for (const attachment of attachments) { for (const attachment of attachments) {
const contentType = await fetch(attachment.url, { const type = attachment.type?.toLowerCase();
method: "HEAD",
}).then((res) => res.headers.get("Content-Type"));
if (contentType) { if (type.startsWith("image")) {
if (contentType.startsWith("image/")) { images.push({
images.push({ media: {url: attachment.url},
url: attachment.url, description: attachment.description ?? attachment.comment,
desc: attachment.description ?? attachment.comment, });
type: contentType, } else if (type.startsWith("video")) {
}); videos.push({
} else if (contentType.startsWith("video/")) { media: {url: attachment.url},
videos.push({ description: attachment.description ?? attachment.comment,
url: attachment.url, });
desc: attachment.description ?? attachment.comment, } else if (type.startsWith("audio")) {
type: contentType, audios.push({
}); url: attachment.url,
} else if (contentType.startsWith("audio/")) { description: attachment.description ?? attachment.comment,
audios.push({ });
url: attachment.url,
desc: attachment.description ?? attachment.comment,
type: contentType,
});
}
} else {
const type = attachment.type?.toLowerCase();
const fileType =
attachment.pleroma?.mime_type ?? type.indexOf("/") > -1
? type
: type +
"/" +
(url.match(/\.([a-z0-9]{3,4})$/)?.[0] ?? type == "image" ? "png" : type == "video" ? "mp4" : "mpeg");
if (type.startsWith("image")) {
images.push({
url: attachment.url,
desc: attachment.description ?? attachment.comment,
type: fileType,
});
} else if (type.startsWith("video")) {
videos.push({
url: attachment.url,
desc: attachment.description ?? attachment.comment,
type: fileType,
});
} else if (type.startsWith("audio")) {
audios.push({
url: attachment.url,
desc: attachment.description ?? attachment.comment,
type: fileType,
});
}
} }
} }
} }
@ -1156,19 +1120,19 @@ async function processUrl(msg, url, spoiler = false, command = false) {
if (postData.inReplyTo) { if (postData.inReplyTo) {
contextUrl = postData.inReplyTo; contextUrl = postData.inReplyTo;
context = "Replying to: "; context = `-# ${Icons.fedimbed.reply} Replying to: `;
const replyData = await fetchPost(postData.inReplyTo, platform); const replyData = await fetchPost(postData.inReplyTo, platform);
if (replyData) { if (replyData) {
if (replyData._fedimbed_mastoapi) { if (replyData._fedimbed_mastoapi) {
context += `${ context += `[${
replyData.account?.display_name ?? replyData.account?.display_name ??
replyData.account?.username ?? replyData.account?.username ??
replyData.user?.name ?? replyData.user?.name ??
replyData.user?.username replyData.user?.username
} (@${ } (@${
replyData.account?.fqn ?? `${replyData.account?.username ?? replyData.user?.username}@${urlObj.hostname}` replyData.account?.fqn ?? `${replyData.account?.username ?? replyData.user?.username}@${urlObj.hostname}`
})`; })](${contextUrl})`;
} else { } else {
const authorData = await signedFetch(replyData.actor ?? replyData.attributedTo, { const authorData = await signedFetch(replyData.actor ?? replyData.attributedTo, {
headers: { headers: {
@ -1183,13 +1147,13 @@ async function processUrl(msg, url, spoiler = false, command = false) {
if (authorData) { if (authorData) {
const authorUrlObj = new URL(authorData.url ?? authorData.id); const authorUrlObj = new URL(authorData.url ?? authorData.id);
context += `${authorData.name} (${authorData.preferredUsername}@${authorUrlObj.hostname})`; context += `[${authorData.name} (${authorData.preferredUsername}@${authorUrlObj.hostname})](${contextUrl})`;
} else { } else {
// bootleg author // bootleg author
const authorUrl = replyData.actor ?? replyData.attributedTo; const authorUrl = replyData.actor ?? replyData.attributedTo;
const authorUrlObj = new URL(authorUrl); const authorUrlObj = new URL(authorUrl);
const name = authorUrlObj.pathname.substring(authorUrlObj.pathname.lastIndexOf("/") + 1); const name = authorUrlObj.pathname.substring(authorUrlObj.pathname.lastIndexOf("/") + 1);
context += `${name}@${authorUrlObj.hostname}`; context += `[${name}@${authorUrlObj.hostname}](${authorUrl})`;
} }
} }
} else { } else {
@ -1201,36 +1165,18 @@ async function processUrl(msg, url, spoiler = false, command = false) {
// NB: everyone else except gts doesnt follow the spec (they should be using attachments) // NB: everyone else except gts doesnt follow the spec (they should be using attachments)
const attachments = Array.isArray(postData.attachment) ? postData.attachment : [postData.attachment]; const attachments = Array.isArray(postData.attachment) ? postData.attachment : [postData.attachment];
for (const attachment of attachments) { for (const attachment of attachments) {
if (attachment.mediaType) { if (attachment.url) {
if (attachment.mediaType.startsWith("video/")) { const type = attachment.type?.toLowerCase();
videos.push({
url: attachment.url,
desc: attachment.name ?? attachment.description ?? attachment.comment,
type: attachment.mediaType,
});
} else if (attachment.mediaType.startsWith("image/")) {
images.push({
url: attachment.url,
desc: attachment.name ?? attachment.description ?? attachment.comment,
type: attachment.mediaType,
});
} else if (attachment.mediaType.startsWith("audio/")) {
audios.push({
url: attachment.url,
desc: attachment.name ?? attachment.description ?? attachment.comment,
type: attachment.mediaType,
});
}
} else if (attachment.url) {
let attUrl = attachment.url; let attUrl = attachment.url;
if (Array.isArray(attachment.url)) { if (Array.isArray(attachment.url)) {
switch (attachment.type) { switch (type) {
case "Image": { case "image": {
const newUrl = attachment.url.find((a) => a.mediaType?.startsWith("image/"))?.href; const newUrl = attachment.url.find((a) => a.mediaType?.startsWith("image/"))?.href;
if (newUrl) attUrl = newUrl; if (newUrl) attUrl = newUrl;
break; break;
} }
case "Video": { case "video": {
const newUrl = attachment.url.find((a) => a.mediaType?.startsWith("video/"))?.href; const newUrl = attachment.url.find((a) => a.mediaType?.startsWith("video/"))?.href;
if (newUrl) attUrl = newUrl; if (newUrl) attUrl = newUrl;
break; break;
@ -1240,60 +1186,21 @@ async function processUrl(msg, url, spoiler = false, command = false) {
} }
} }
let contentType; if (type.startsWith("image")) {
if (attUrl != null) images.push({
contentType = await fetch(attUrl, { media: {url: attUrl},
method: "HEAD", description: attachment.name ?? attachment.description ?? attachment.comment,
}).then((res) => res.headers.get("Content-Type")); });
} else if (type.startsWith("video")) {
if (contentType) { videos.push({
if (contentType.startsWith("image/")) { media: {url: attUrl},
images.push({ description: attachment.name ?? attachment.description ?? attachment.comment,
url: attUrl, });
desc: attachment.name ?? attachment.description ?? attachment.comment, } else if (type.startsWith("audio")) {
type: contentType, audios.push({
}); url: attUrl,
} else if (contentType.startsWith("video/")) { description: attachment.name ?? attachment.description ?? attachment.comment,
videos.push({ });
url: attUrl,
desc: attachment.name ?? attachment.description ?? attachment.comment,
type: contentType,
});
} else if (contentType.startsWith("audio/")) {
audios.push({
url: attUrl,
desc: attachment.name ?? attachment.description ?? attachment.comment,
type: contentType,
});
}
} else {
const type = attachment.type?.toLowerCase();
const fileType =
type.indexOf("/") > -1
? type
: type +
"/" +
(url.match(/\.([a-z0-9]{3,4})$/)?.[0] ?? type == "image" ? "png" : type == "video" ? "mp4" : "mpeg");
if (type.startsWith("image")) {
images.push({
url: attUrl,
desc: attachment.name ?? attachment.description ?? attachment.comment,
type: fileType,
});
} else if (type.startsWith("video")) {
videos.push({
url: attUrl,
desc: attachment.name ?? attachment.description ?? attachment.comment,
type: fileType,
});
} else if (type.startsWith("audio")) {
audios.push({
url: attUrl,
desc: attachment.name ?? attachment.description ?? attachment.comment,
type: fileType,
});
}
} }
} else { } else {
logger.warn("fedimbed", `Unhandled attachment structure! ${JSON.stringify(attachment)}`); logger.warn("fedimbed", `Unhandled attachment structure! ${JSON.stringify(attachment)}`);
@ -1306,14 +1213,8 @@ async function processUrl(msg, url, spoiler = false, command = false) {
} }
if (postData.image?.url) { if (postData.image?.url) {
const imageUrl = new URL(postData.image.url);
const contentType = await fetch(postData.image.url, {
method: "HEAD",
}).then((res) => res.headers.get("Content-Type"));
images.push({ images.push({
url: postData.image.url, media: {url: postData.image.url},
desc: "",
type: contentType ?? "image/" + imageUrl.pathname.substring(imageUrl.pathname.lastIndexOf(".") + 1),
}); });
} }
@ -1328,7 +1229,7 @@ async function processUrl(msg, url, spoiler = false, command = false) {
}) })
.then((res) => res.json()) .then((res) => res.json())
.catch((err) => { .catch((err) => {
/*if (platform !== "cohost")*/ logger.error("fedimbed", `Failed to get author for "${url}": ${err}`); logger.error("fedimbed", `Failed to get author for "${url}": ${err}`);
}); });
if (authorData) { if (authorData) {
@ -1394,31 +1295,15 @@ async function processUrl(msg, url, spoiler = false, command = false) {
let desc = ""; let desc = "";
let MAX_LENGTH = 3999; let MAX_LENGTH = 3999;
if ((cw != "" || sensitive) && images.length == 0 && videos.length == 0 && audios.length == 0) { if (cw != "" || sensitive) {
const ors = content.split("||"); const ors = content.split("||");
desc += `||${content.replaceAll("||", "|\u200b|")}||`; desc += `||${content.replaceAll("||", "|\u200b|")}||`;
MAX_LENGTH -= ors.length - 1; MAX_LENGTH -= ors.length - 1;
MAX_LENGTH -= 4; MAX_LENGTH -= 4;
if (cw != "") {
desc = "\u26a0 " + cw + "\n\n" + desc;
MAX_LENGTH -= 4 - cw.length;
}
} else { } else {
desc = content; desc = content;
} }
if (desc.length > MAX_LENGTH) {
if (desc.endsWith("||")) {
desc = desc.substring(0, MAX_LENGTH - 2);
desc += "\u2026||";
} else {
desc = desc.substring(0, MAX_LENGTH) + "\u2026";
}
}
let user = author.name ? `${author.name} (${author.handle})` : author.handle;
const crawled = await getCrawledData(url, color, platformName); const crawled = await getCrawledData(url, color, platformName);
if (!color && crawled?.color) { if (!color && crawled?.color) {
color = crawled.color; color = crawled.color;
@ -1429,328 +1314,184 @@ async function processUrl(msg, url, spoiler = false, command = false) {
if (platformName.includes("Nitter") && platformName.includes(" \u2022 ")) { if (platformName.includes("Nitter") && platformName.includes(" \u2022 ")) {
const [nn, ns] = platformName.split(" \u2022 "); const [nn, ns] = platformName.split(" \u2022 ");
stats = ns; stats = ns
.replace("\u21a9", Icons.fedimbed.reply)
.replace("\ud83d\udd01", Icons.fedimbed.repost)
.replace("\u2198", Icons.fedimbed.quote)
.replace("\u2665", Icons.fedimbed.like)
.replace("\ud83d\udd16", Icons.fedimbed.bookmark)
.replace("\ud83d\udc41", Icons.fedimbed.views)
.replaceAll(/ <:i:/g, "\u3000<:i:");
platformName = nn; platformName = nn;
} }
if (platformName == "Nitter") { if (platformName == "Nitter") {
const newHandle = author.handle.split("@")[0]; const newHandle = author.handle.split("@")[0];
user = `${author.name} (@${newHandle})`; author.handle = "@" + newHandle;
if (context) { if (context) {
const contextHandle = context.match(/\(([^@]+?@.+?)\)/)?.[1]; const contextHandle = context.match(/\(([^@]+?@.+?)\)/)?.[1];
if (contextHandle) { if (contextHandle) {
const newContextHandle = "@" + contextHandle.split("@")[0]; const newContextHandle = contextHandle.split("@")[0];
context = context.replace(contextHandle, newContextHandle); context = context.replace(contextHandle, "@" + newContextHandle);
context = context.replace(/: (.+?)$/, `: [$1](${contextUrl})`);
} }
} }
} }
const baseEmbed = { const warningText = {
color, type: 10,
url, content: `## ${cw}`,
timestamp,
description: desc,
title: title ?? user,
author: title
? {
name: user,
url: author.url,
}
: context
? {
name: context,
url: contextUrl,
icon_url: "https://cdn.discordapp.com/emojis/1308640078825787412.png",
}
: null,
footer: {
icon_url: crawled?.icon,
text: (stats != null && stats != "" ? stats + "\n" : "") + platformName,
},
thumbnail: {
url: author.avatar,
},
fields: [],
}; };
if (images.length > 0) {
if (images.length > 1) {
const links = images.map((attachment, index) => `[Image ${index + 1}](${attachment.url})`).join("\u3000\u3000");
if (links.length <= 1024) const container = {
baseEmbed.fields.push({ type: 17,
name: "Images", accent_color: color,
value: links, components: [],
inline: true, spoiler,
}); };
let headerContent = `${author.name ? `## ${author.name}\n` : ""}-# [${author.handle}](${author.url})`;
if (title) headerContent += "\n### " + title;
MAX_LENGTH -= headerContent.length + 1;
if (desc.length > MAX_LENGTH) {
if (desc.endsWith("||")) {
desc = desc.substring(0, MAX_LENGTH - 2);
desc += "\u2026||";
} else { } else {
baseEmbed.fields.push({ desc = desc.substring(0, MAX_LENGTH) + "\u2026";
name: "Image",
value: `[Click for image](${images[0].url})`,
inline: true,
});
}
}
if (videos.length > 0) {
if (videos.length > 1) {
baseEmbed.fields.push({
name: "Videos",
value: videos.map((attachment, index) => `[Video ${index + 1}](${attachment.url})`).join("\u3000\u3000"),
inline: true,
});
} else {
baseEmbed.fields.push({
name: "Video",
value: `[Click for video](${videos[0].url})`,
inline: true,
});
}
}
if (audios.length > 0) {
if (audios.length > 1) {
baseEmbed.fields.push({
name: "Audios",
value: audios.map((attachment, index) => `[Audio ${index + 1}](${attachment.url})`).join("\u3000\u3000"),
inline: true,
});
} else {
baseEmbed.fields.push({
name: "Audio",
value: `[Click for audio](${audios[0].url})`,
inline: true,
});
} }
} }
headerContent += "\n" + desc;
const header = [
context && {
type: 10,
content: context,
},
{
type: 9,
components: [
{
type: 10,
content: headerContent,
},
],
accessory: {
type: 11,
media: {
url: author.avatar,
},
},
},
].filter((x) => !!x);
container.components.push(...header);
if (poll) { if (poll) {
const pollTime = poll.end.getTime(); const pollTime = poll.end.getTime();
const now = Date.now(); const now = Date.now();
baseEmbed.fields.push({ container.components.push({
name: "Poll", type: 10,
value: content:
poll.options poll.options
.map((o) => { .map((o) => {
const percent = o.count / poll.total; const percent = o.count / poll.total;
const bar = Math.round(percent * 32); const bar = Math.round(percent * 32);
return `**${o.name}** (${numberFormatter.format(o.count)}, ${Math.round( return `> **${o.name}** (${numberFormatter.format(o.count)}, ${Math.round(
percent * 100 percent * 100
)}%)\n\`${"\u2588".repeat(bar)}${" ".repeat(32 - bar)}\``; )}%)> \n\`${"\u2588".repeat(bar)}${" ".repeat(32 - bar)}\``;
}) })
.join("\n\n") + .join("> \n> \n") +
`\n\n${poll.total} votes \u2022 End${pollTime > now ? "s" : "ed"} <t:${Math.floor(pollTime / 1000)}:R>`, `> \n> \n${poll.total} votes \u2022 End${pollTime > now ? "s" : "ed"} <t:${Math.floor(pollTime / 1000)}:R>`,
}); });
} }
let sendWait = false; const footer = {
if (videos.length > 0 || audios.length > 0 || images.length > 4) { type: 9,
sendWait = true; components: [
if (msg instanceof Message) await msg.addReaction("\uD83D\uDCE4"); {
type: 10,
content: `-# ${stats}\n${platformName} \u2022 <t:${Math.floor(new Date(timestamp).getTime() / 1000)}:F>`,
},
],
accessory: {
type: 2,
style: 5,
label: "View Post",
url,
},
};
for (const image in images) {
if (image.description?.length === 0) image.description = null;
} }
const embeds = [];
const files = [];
const guild = msg.channel?.guild ?? (msg.guildID ? hf.bot.guilds.get(msg.guildID) : false);
let limit = getUploadLimit(guild);
if (msg.attachmentSizeLimit != null) limit = msg.attachmentSizeLimit;
if (images.length > 0) { if (images.length > 0) {
if (images.length <= 4) { if (images.length > 10) {
for (const attachment of images) { while (images.length > 10) {
const embed = Object.assign({}, baseEmbed); container.components.push({
embed.image = { type: 12,
url: attachment.url, items: images.splice(0, 10),
description: attachment.desc,
};
embeds.push(embed);
}
} else if (images.length > 4 && images.length <= 10) {
for (const attachment of images) {
const size = await fetch(attachment.url, {
method: "HEAD",
headers: {
"User-Agent": FRIENDLY_USERAGENT,
},
}).then((res) => Number(res.headers.get("Content-Length")));
if (size <= limit) {
const file = await fetch(attachment.url, {
headers: {
"User-Agent": FRIENDLY_USERAGENT,
},
})
.then((res) => res.arrayBuffer())
.then((buf) => Buffer.from(buf));
files.push({
filename:
(cw != "" || spoiler ? "SPOILER_" : "") +
(attachment.type.indexOf("/") > -1
? attachment.type.replace("/", ".")
: attachment.type + "." + (url.match(/\.([a-z0-9]{3,4})$/)?.[0] ?? "png")),
file,
description: attachment.desc,
});
}
}
embeds.push(baseEmbed);
} else {
const ten = images.slice(0, 10);
for (const attachment of ten) {
const size = await fetch(attachment.url, {
method: "HEAD",
headers: {
"User-Agent": FRIENDLY_USERAGENT,
},
}).then((res) => Number(res.headers.get("Content-Length")));
if (size <= limit) {
const file = await fetch(attachment.url, {
headers: {
"User-Agent": FRIENDLY_USERAGENT,
},
})
.then((res) => res.arrayBuffer())
.then((buf) => Buffer.from(buf));
files.push({
filename:
(cw != "" || spoiler ? "SPOILER_" : "") +
(attachment.type.indexOf("/") > -1
? attachment.type.replace("/", ".")
: attachment.type + "." + (url.match(/\.([a-z0-9]{3,4})$/)?.[0] ?? "png")),
file,
description: attachment.desc,
});
}
}
if (images.length <= 14) {
const fourteen = images.slice(10, 14);
for (const attachment of fourteen) {
const embed = Object.assign({}, baseEmbed);
embed.image = {
url: attachment.url,
description: attachment.desc,
};
embeds.push(embed);
}
} else if (images.length <= 18) {
const fourteen = images.slice(10, 14);
for (const attachment of fourteen) {
const embed = Object.assign({}, baseEmbed);
embed.image = {
url: attachment.url,
description: attachment.desc,
};
embeds.push(embed);
}
const eighteen = images.slice(14, 18);
const _embed = {
color: baseEmbed.color,
url: baseEmbed.url + "?_",
title: "Additional Images",
};
for (const attachment of eighteen) {
const embed = Object.assign({}, _embed);
embed.image = {
url: attachment.url,
description: attachment.desc,
};
embeds.push(embed);
}
}
}
} else {
embeds.push(baseEmbed);
}
if (videos.length > 0) {
for (const attachment of videos) {
const size = await fetch(attachment.url, {
method: "HEAD",
headers: {
"User-Agent": FRIENDLY_USERAGENT,
},
}).then((res) => Number(res.headers.get("Content-Length")));
if (size <= limit) {
const file = await fetch(attachment.url, {
headers: {
"User-Agent": FRIENDLY_USERAGENT,
},
})
.then((res) => res.arrayBuffer())
.then((buf) => Buffer.from(buf));
files.push({
filename:
(cw != "" || spoiler ? "SPOILER_" : "") +
(attachment.type.indexOf("/") > -1
? attachment.type.replace("/", ".").replace("quicktime", "mov")
: attachment.type + "." + (url.match(/\.([a-z0-9]{3,4})$/)?.[0] ?? "mp4")),
file,
description: attachment.desc,
}); });
} }
} }
container.components.push({
type: 12,
items: images,
});
} }
for (const video of videos) {
if (video.description?.length === 0) video.description = null;
container.components.push({
type: 12,
items: [video],
});
}
if (audios.length > 0) { if (audios.length > 0) {
for (const attachment of audios) { container.components.push(
const size = await fetch(attachment.url, { {
method: "HEAD", type: 10,
headers: { content: "### Audio Attachments",
"User-Agent": FRIENDLY_USERAGENT, },
}, {
}).then((res) => Number(res.headers.get("Content-Length"))); type: 1,
components: audios.map((a) => ({
if (size <= limit) { type: 2,
const file = await fetch(attachment.url, { style: 5,
headers: { emoji: {name: "silk_sound", id: "1273119755376529418", animated: false},
"User-Agent": FRIENDLY_USERAGENT, label:
}, a.description?.length > 0
}) ? `"${a.description.length > 78 ? a.description.substring(0, 77) + "\u2026" : a.description}"`
.then((res) => res.arrayBuffer()) : "Audio",
.then((buf) => Buffer.from(buf)); url: a.url,
})),
files.push({
filename:
(cw != "" || spoiler ? "SPOILER_" : "") +
(attachment.type.indexOf("/") > -1
? attachment.type.replace("/", ".").replace("mpeg", "mp3").replace("vnd.wave", "wav").replace("x-", "")
: attachment.type + "." + (url.match(/\.([a-z0-9]{3,4})$/)?.[0] ?? "mp3")),
file,
description: attachment.desc,
});
} }
} );
} }
container.components.push(footer);
if (quoteRes) { if (quoteRes) {
if (!sendWait && quoteRes.sendWait) sendWait = true; const quoteComponents = quoteRes.response.components[0].components;
files.push(...quoteRes.response.attachments); const quoteContext = `-# ${Icons.fedimbed.quote} Quoted Post`;
const quoteEmbed = quoteRes.response.embeds[0]; if (quoteComponents[0].type == 10) {
quoteEmbed.author = {name: "Quoted Post", icon_url: "https://cdn.discordapp.com/emojis/1308640087759654922.png"}; quoteComponents[0].content = quoteContext + "\n" + quoteComponents[0].content;
embeds.push(quoteEmbed); } else {
quoteComponents.splice(0, 0, {type: 10, content: quoteContext});
}
container.components.push({type: 14}, ...quoteComponents);
} }
return { return {
response: { response: {
content: flags: 1 << 15,
cw != "" && (images.length > 0 || videos.length > 0 || audios.length > 0) components: [cw.length > 0 ? warningText : false, container].filter((x) => !!x),
? `:warning: ${cw} || ${url} ||`
: spoiler
? `|| ${url} ||`
: "",
embeds,
attachments: files,
allowedMentions: { allowedMentions: {
repliedUser: false, repliedUser: false,
}, },
@ -1758,7 +1499,6 @@ async function processUrl(msg, url, spoiler = false, command = false) {
messageID: msg.id, messageID: msg.id,
}, },
}, },
sendWait,
}; };
} }