fedimbed: attempt to resolve fedi users from bridgy bsky users

This commit is contained in:
Cynthia Foxwell 2025-04-05 12:25:12 -06:00
parent 12a2e222b7
commit b72ddd9614
Signed by: Cynosphere
SSH key fingerprint: SHA256:H3SM8ufP/uxqLwKSH7xY89TDnbR9uOHzjLoBr0tlajk

View file

@ -143,11 +143,69 @@ async function resolvePlatform(url) {
function normalizePlatform(platform) {
return platform
.replace("gotosocial", "GoToSocial")
.replace("birdsitelive", '"Twitter" (BirdsiteLive)')
.replace("birdsitelive", "BirdsiteLive")
.replace(/^(.)/, (_, c) => c.toUpperCase())
.replace("Cohost", "cohost");
}
async function getCrawledData(url, color, platformName) {
const urlObj = new URL(url);
let headTag,
lastIconSize = 0,
icon;
try {
const page = await fetch(url, {
headers: {
"User-Agent": FRIENDLY_USERAGENT,
},
})
.then((res) => res.text())
.catch(() => {});
if (page) {
headTag = pageParser.parse(page)?.html?.head;
}
} catch {
// noop
}
if (headTag) {
for (const tag of headTag.link) {
if (tag.$rel == "icon" || tag.$rel == "apple-touch-icon") {
if (tag.$sizes) {
const [w, h] = tag.$sizes.split("x").map((x) => parseInt(x));
const size = w * h;
if (size > lastIconSize) {
lastIconSize = size;
icon = tag.$href;
}
} else {
icon = tag.$href;
}
}
}
for (const tag of headTag.meta) {
if (tag.$property == "og:site_name" && tag.$content != platformName) {
if (platformName == "<no nodeinfo>") {
platformName = tag.$content;
} else {
platformName = `${tag.$content} (${platformName})`;
}
} else if (!color && tag.$name == "theme-color") {
color = parseInt(tag.$content.replace("^#", "0x"));
}
}
}
if (icon && icon.startsWith("/")) {
icon = urlObj.origin + icon;
}
return {icon, color, platformName};
}
const keyId = "https://hf.c7.pm/actor#main-key";
const privKey = fs.readFileSync(require.resolve("#root/priv/private.pem"));
async function signedFetch(url, options) {
@ -280,6 +338,48 @@ async function blueskyQuoteEmbed(quote) {
timestamp: quote.value.createdAt,
};
if (quote.author.handle.endsWith(".ap.brid.gy")) {
const handle = quote.author.handle.replace(".ap.brid.gy", "");
const split = handle.split(".");
const username = split.shift();
const domain = split.join(".");
const authorUrl = `https://${domain}/users/${username}`;
const authorData = await signedFetch(authorUrl, {
headers: {
"User-Agent": FRIENDLY_USERAGENT,
Accept: "application/activity+json",
},
})
.then((res) => res.json())
.catch((err) => {
logger.error("fedimbed", `Failed to get author for "${authorUrl}": ${err}`);
});
if (authorData) {
const platform = (await resolvePlatform(authorUrl)) ?? "<no nodeinfo>";
let color = PLATFORM_COLORS[platform];
let platformName = normalizePlatform(platform);
const crawled = getCrawledData(authorUrl, color, platformName);
if (!color && crawled?.color) {
color = crawled.color;
}
if (crawled?.platformName) {
platformName = crawled.platformName;
}
platformName += " [via Bluesky via Bridgy]";
mainEmbed.footer = {
text: platformName,
icon_url: crawled?.icon,
};
mainEmbed.title = `${authorData.name} (${authorData.preferredUsername}@${domain})`;
mainEmbed.color = color;
}
}
if (quote.value.facets?.length > 0) {
mainEmbed.description = processBlueskyFacets(mainEmbed.description, quote.value.facets);
}
@ -353,7 +453,6 @@ async function blueskyQuoteEmbed(quote) {
async function bluesky(msg, url, spoiler = false) {
const quoteOnly = await hasFlag(msg.guildID, "bskyQuoteOnly");
// really...
if (url.includes("bsky.brid.gy")) url = url.replace("bsky.brid.gy/r/https://", "");
const urlObj = new URL(url);
@ -429,6 +528,48 @@ async function bluesky(msg, url, spoiler = false) {
timestamp: post.record.createdAt,
};
if (post.author.handle.endsWith(".ap.brid.gy")) {
const handle = post.author.handle.replace(".ap.brid.gy", "");
const split = handle.split(".");
const username = split.shift();
const domain = split.join(".");
const authorUrl = `https://${domain}/@${username}`;
const authorData = await signedFetch(authorUrl, {
headers: {
"User-Agent": FRIENDLY_USERAGENT,
Accept: "application/activity+json",
},
})
.then((res) => res.json())
.catch((err) => {
logger.error("fedimbed", `Failed to get author for "${authorUrl}": ${err}`);
});
if (authorData) {
const platform = (await resolvePlatform(authorUrl)) ?? "<no nodeinfo>";
let color = PLATFORM_COLORS[platform];
let platformName = normalizePlatform(platform);
const crawled = getCrawledData(authorUrl, color, platformName);
if (!color && crawled?.color) {
color = crawled.color;
}
if (crawled?.platformName) {
platformName = crawled.platformName;
}
platformName += " [via Bluesky via Bridgy]";
mainEmbed.footer = {
text: platformName,
icon_url: crawled?.icon,
};
mainEmbed.title = `${authorData.name} (${authorData.preferredUsername}@${domain})`;
mainEmbed.color = color;
}
}
if (post.record.facets?.length > 0) {
mainEmbed.description = processBlueskyFacets(mainEmbed.description, post.record.facets);
}
@ -1220,56 +1361,12 @@ async function processUrl(msg, url, spoiler = false, command = false) {
const user = author.name ? `${author.name} (${author.handle})` : author.handle;
let headTag,
lastIconSize = 0,
icon;
try {
const page = await fetch(url, {
headers: {
"User-Agent": FRIENDLY_USERAGENT,
},
})
.then((res) => res.text())
.catch(() => {});
if (page) {
headTag = pageParser.parse(page)?.html?.head;
}
} catch {
// noop
const crawled = await getCrawledData(url, color, platformName);
if (!color && crawled?.color) {
color = crawled.color;
}
if (headTag) {
for (const tag of headTag.link) {
if (tag.$rel == "icon" || tag.$rel == "apple-touch-icon") {
if (tag.$sizes) {
const [w, h] = tag.$sizes.split("x").map((x) => parseInt(x));
const size = w * h;
if (size > lastIconSize) {
lastIconSize = size;
icon = tag.$href;
}
} else {
icon = tag.$href;
}
}
}
for (const tag of headTag.meta) {
if (tag.$property == "og:site_name" && tag.$content != platformName) {
if (platformName == "<no nodeinfo>") {
platformName = tag.$content;
} else {
platformName = `${tag.$content} (${platformName})`;
}
} else if (!color && tag.$name == "theme-color") {
color = parseInt(tag.$content.replace("^#", "0x"));
}
}
}
if (icon && icon.startsWith("/")) {
icon = urlObj.origin + icon;
if (crawled?.platformName) {
platformName = crawled.platformName;
}
const baseEmbed = {
@ -1291,7 +1388,7 @@ async function processUrl(msg, url, spoiler = false, command = false) {
}
: null,
footer: {
icon_url: icon,
icon_url: crawled?.icon,
text: platformName,
},
thumbnail: {