123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
// ==UserScript==
// @name Bluesky Post Embedder
// @version 1.1
// @description Embeds Bluesky posts in Xenforo-compatible forums and adjusts iframe height dynamically.
// @match *://*/*
// ==/UserScript==
(function() {
'use strict';
const blueskyRegex = /https:\/\/bsky\.app\/profile\/(?:did:plc:[^\/]+|[^\/]+)\/post\/[^\/]+/;
const EMBED_URL = 'https://embed.bsky.app';
function handleToDid(userHandle) {
return fetch(`https://api.allorigins.win/raw?url=https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=${userHandle}`)
.then(response => response.text())
.then(data => JSON.parse(data))
.then(jsonData => jsonData.did);
}
async function createBlueskyIframe(link) {
const href = link.getAttribute('href');
let postUsername, postID;
if (href.includes("did:plc:")) {
postUsername = href.split("/")[4];
} else if (!href.startsWith("did:")) {
try {
postUsername = await handleToDid(href.split("/")[4]);
} catch (error) {
console.error("Error resolving handle:", error);
return;
}
} else {
postUsername = href;
}
const urlParts = href.split("/");
if (urlParts[3] === "profile") {
postID = urlParts[6];
} else {
postID = urlParts[6];
}
const embedHTML = `
<div class="bluesky-embed-container" style="max-width: 100%; margin: 0 auto; overflow: hidden;">
<iframe src="https://embed.bsky.app/embed/${postUsername}/app.bsky.feed.post/${postID}"
frameborder="0"
width="100%"
style="border: none; display: block; flex-grow: 1;"
scrolling="no"
allowtransparency="true"
title="Bluesky post"
data-bluesky-id="bluesky-${postID}">
</iframe>
<script async src="https://embed.bsky.app/static/embed.js"
data-handle="${postUsername}"
data-skeet="${postID}">
</script>
</div>
`;
link.outerHTML = embedHTML;
}
function replaceLinks() {
const links = document.querySelectorAll('a[href]');
links.forEach(link => {
if (link.href.match(blueskyRegex)) {
createBlueskyIframe(link).catch(error => console.error("Error creating iframe:", error));
}
});
}
function adjustIframeHeight(event) {
if (event.origin !== EMBED_URL) {
console.warn('Received message from unauthorized origin:', event.origin);
return;
}
const id = event.data.id;
const height = event.data.height;
if (height) {
if (id) {
const embed = document.querySelector(`[data-bluesky-id="${id}"]`);
if (embed) {
console.log(`Setting height for iframe ID ${id} to ${height}px`);
embed.style.height = `${height}px`;
} else {
console.warn('No matching iframe found for ID:', id);
}
} else {
// Handle cases where ID is null
const iframes = document.querySelectorAll('iframe[data-bluesky-id]');
iframes.forEach((iframe) => {
console.log('Setting height for iframe without ID to', height, 'px');
iframe.style.height = `${height}px`;
});
}
} else {
console.warn('Received message without height data:', event);
}
}
// Use MutationObserver to handle dynamic content loading
const observer = new MutationObserver((mutationsList, observer) => {
for (let mutation of mutationsList) {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) { // Element node
replaceLinks();
}
});
}
}
});
observer.observe(document.body, { childList: true, subtree: true });
addEventListener("load", function() {
replaceLinks();
});
// Add message listener for iframe height adjustment
window.addEventListener('message', adjustIframeHeight);
})();