cohost-wc/bookmarklet.cjs

152 lines
8.4 KiB
JavaScript
Raw Normal View History

(async () => {
const COHOST_CDN_BASE = "https://staging.cohostcdn.org/";
const COHOST_STATIC_BASE = "https://cohost.org/static/";
const CORS_PROXY_BASE = "https://cohost-web-component.meow.garden/";
const OUTPUT_DIV_ID = "cohost-wc-bookmarklet-output";
const MEDIA_FLAG_DIV_ID = "cohost-wc-bookmarklet-media-flag";
const AUDIO_PLAYER_FLAG_DIV_ID = "cohost-wc-audio-player-flag";
async function maybeConvertToDataUri(imageUrl, shouldConvert) {
if (!shouldConvert) { return imageUrl; }
let proxyUrl;
if (imageUrl.startsWith(COHOST_CDN_BASE)) {
proxyUrl = imageUrl.replace(COHOST_CDN_BASE, CORS_PROXY_BASE + "cohostcdn-cors-proxy/");
if (imageUrl.includes("/avatar/")) {
proxyUrl += "?dpr=2&width=32&height=32&fit=cover&auto=webp";
}
} else if (imageUrl.startsWith(COHOST_STATIC_BASE)) {
proxyUrl = imageUrl.replace(COHOST_STATIC_BASE, CORS_PROXY_BASE + "cohost-static-cors-proxy/");
} else {
return imageUrl;
}
let response = await fetch(proxyUrl);
let blob = await response.blob();
return new Promise((resolve) => {
let reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.readAsDataURL(blob);
});
}
2024-09-18 17:57:16 -07:00
async function assembleWebComponent(dataUris) {
let trpcState = JSON.parse(document.getElementById("trpc-dehydrated-state").innerText);
let postData = trpcState.queries.find((q) => q.queryKey[0].includes("singlePost")).state.data.post;
let postElement = document.createElement("cohost-post");
postElement.setAttribute("avatarSrc", await maybeConvertToDataUri(postData.postingProject.avatarURL, dataUris));
postElement.setAttribute("avatarShape", postData.postingProject.avatarShape);
postElement.setAttribute("comments", postData.numComments);
postElement.setAttribute("displayName", postData.postingProject.displayName);
postElement.setAttribute("handle", postData.postingProject.handle);
postElement.setAttribute("permalink", postData.singlePostPageUrl);
if (postData.publishedAt) {
postElement.setAttribute("publishedAt", postData.publishedAt);
2024-09-18 17:57:16 -07:00
}
if (postData.numSharedComments) {
postElement.setAttribute("sharedComments", postData.numSharedComments);
2024-09-18 17:57:16 -07:00
}
if (postData.headline) {
postElement.setAttribute("singlePostHeadline", postData.headline);
}
postElement.setAttribute("tags", postData.tags.join(","));
if (postData.shareTree && postData.shareTree.length) {
postElement.setAttribute("sharedItems", "");
let sharedFrom = postData.shareTree[postData.shareTree.length - 1];
postElement.setAttribute("sharedAvatarSrc", await maybeConvertToDataUri(sharedFrom.postingProject.avatarURL, dataUris));
postElement.setAttribute("sharedAvatarShape", sharedFrom.postingProject.avatarShape);
postElement.setAttribute("sharedDisplayName", sharedFrom.postingProject.displayName);
postElement.setAttribute("sharedHandle", sharedFrom.postingProject.handle);
let shareTree = [...postData.shareTree, postData];
for (sharedPost of shareTree) {
if (sharedPost.transparentShareOfPostId !== null) {
continue;
}
let sharedElement = document.createElement("cohost-shared-item");
sharedElement.setAttribute("avatarSrc", await maybeConvertToDataUri(sharedPost.postingProject.avatarURL, dataUris));
sharedElement.setAttribute("avatarShape", sharedPost.postingProject.avatarShape);
sharedElement.setAttribute("displayName", sharedPost.postingProject.displayName);
sharedElement.setAttribute("handle", sharedPost.postingProject.handle);
if (sharedPost.headline) {
sharedElement.setAttribute("headline", sharedPost.headline);
}
sharedElement.setAttribute("permalink", sharedPost.singlePostPageUrl);
if (sharedPost.publishedAt) {
sharedElement.setAttribute("publishedAt", sharedPost.publishedAt);
}
sharedElement.setAttribute("tags", sharedPost.tags.join(","));
let sharedIdElement = document.getElementById(`post-${sharedPost.postId}`);
if (sharedIdElement) {
let sharedPostBody = sharedIdElement.parentElement.querySelector("[data-post-body]");
if (sharedPostBody) {
sharedElement.innerHTML = sharedPostBody.innerHTML;
}
}
postElement.appendChild(sharedElement);
}
} else {
let postIdElement = document.getElementById(`post-${postData.postId}`);
if (postIdElement) {
let postBody = document.getElementById(`post-${postData.postId}`).parentElement.querySelector("[data-post-body]");
if (postBody) {
postElement.innerHTML = postBody.innerHTML;
}
}
2024-09-18 17:57:16 -07:00
}
let mediaFlag = false;
let audioPlayerFlag = false;
for (const mediaElement of postElement.querySelectorAll('img, audio')) {
if (mediaElement.tagName == 'AUDIO') { audioPlayerFlag = true; }
let src = mediaElement.getAttribute("src");
if (dataUris && src.startsWith(COHOST_STATIC_BASE)) {
mediaElement.setAttribute('src', await maybeConvertToDataUri(src, true));
} else if (src.startsWith("https://cohost.org/") || src.startsWith(COHOST_CDN_BASE)) {
mediaFlag = true;
}
}
return {
postElement,
mediaFlag,
audioPlayerFlag,
};
2024-09-18 17:57:16 -07:00
}
async function renderOutput(webComponent, dataUris) {
let template = document.createElement('template');
template.innerHTML = `<div id="${OUTPUT_DIV_ID}" class="fixed bottom-0 p-2 flex flex-col items-center gap-2 font-sm bg-background co-themed-box border rounded-lg">
<textarea rows="5" cols="35" style="font-size: inherit; line-height: 1.4"></textarea>
<div id="${MEDIA_FLAG_DIV_ID}" class="co-info-box co-info text-sm mx-auto w-full rounded-lg p-3">
Post <b>still</b> contains media hosted on cohost.<br />Consider rehosting any images or audio files on your website.
</div>
<div id="${AUDIO_PLAYER_FLAG_DIV_ID}" class="co-info-box co-info text-sm mx-auto w-full rounded-lg p-3">
cohost's audio player doesn't function correctly (yet).
</div>
<div class="flex flex-row gap-1">
<button id="cohost-wc-data-uris-button" class="rounded-lg bg-cherry py-2 px-4 text-sm font-bold text-notWhite hover:bg-cherry-600 active:bg-cherry-700">Convert avatars and custom emoji to data URIs</button>
<button id="cohost-wc-dismiss-button" class="rounded-lg bg-cherry py-2 px-4 text-sm font-bold text-notWhite hover:bg-cherry-600 active:bg-cherry-700">dismiss</button>
</div>
</div>`;
template.content.querySelector('textarea').value = webComponent.postElement.outerHTML;
if (!webComponent.mediaFlag) {
template.content.querySelector(`#${MEDIA_FLAG_DIV_ID}`).remove();
} else if (!dataUris) {
template.content.querySelector(`#${MEDIA_FLAG_DIV_ID} b`).remove();
}
if (!webComponent.audioPlayerFlag) {
template.content.querySelector(`#${AUDIO_PLAYER_FLAG_DIV_ID}`).remove();
}
template.content.querySelector("#cohost-wc-data-uris-button").onclick = async () => {
let webComponent = await assembleWebComponent(true);
renderOutput(webComponent, true);
}
template.content.querySelector("#cohost-wc-dismiss-button").onclick = function() {
document.querySelector(`#${OUTPUT_DIV_ID}`).remove();
}
let existingOutput = document.querySelector(`#${OUTPUT_DIV_ID}`);
if (existingOutput) {
existingOutput.replaceWith(template.content);
} else {
document.body.append(template.content);
}
2024-09-18 17:57:16 -07:00
}
let webComponent = await assembleWebComponent(false);
renderOutput(webComponent, false);
})();