fedimbed: attempt to resolve fedi users from bridgy bsky users
This commit is contained in:
parent
12a2e222b7
commit
b72ddd9614
1 changed files with 149 additions and 52 deletions
|
@ -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: {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue