Embed and aggregate Bluesky and Mastodon replies as blog or static-site comments.
fork

Configure Feed

Select the types of activity you want to include in your feed.

add visual cue

foxihd ca2a5d21 c7a8ee89

+6 -4
+5 -3
index.js
··· 22 22 23 23 const cmtSty = document.createElement('style'); 24 24 cmtSty.textContent = ` 25 - #comments ul {padding-left: 0;list-style: none;} 26 - #comments ul ul {padding-left: 2rem;} 27 - .fed-comments {margin: 1.6rem 0;border-left: 3pt solid var(--ac);background: #faf0e680;padding: 1.618rem;overflow: auto;} 25 + #comments ul {position:relative;padding-left:0;list-style:none;} 26 + #comments ul::before {position: absolute;top: 0;right: 0;bottom: 0;left: 0;z-index: -1;border-left: 3pt solid #80808008;border-radius: 1ex;content: '';} 27 + #comments ul ul {padding-left: 2em} 28 + #comments li {padding-top: 2em;list-style: none;} 29 + .fed-comments {border-left: 3pt solid var(--ac);background: #faf0e680;padding: 1.618rem;overflow: auto;} 28 30 .fed-comments.bsky {--ac: #1185fe;} 29 31 .fed-comments.mstd {--ac: #563acc;} 30 32 .fed-comments > header,.fed-comments > footer {display: flex;align-items: center;gap: 1rem;}
+1 -1
index.min.js
··· 1 - const date=new Date,formatDate=e=>new Date(e).toLocaleString("en-US",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:!1,formatMatcher:"basic"}).replace(",","").replace(/(\d+)\/(\d+)\/(\d+)/,"$3-$1-$2"),toISOString=e=>new Date(e).toISOString(),getElement=e=>document.getElementById(e),getElements=e=>document.querySelectorAll(e),cmt=getElement("comments"),{i18nReplies:i18nReplies,i18nReblogs:i18nReblogs,i18nFavourites:i18nFavourites,i18nLoading:i18nLoading,i18nErr:i18nErr,i18nNocomment:i18nNocomment}=cmt.dataset,cmtSty=document.createElement("style");cmtSty.textContent='\n#comments ul {padding-left: 0;list-style: none;}\n#comments ul ul {padding-left: 2rem;}\n.fed-comments {margin: 1.6rem 0;border-left: 3pt solid var(--ac);background: #faf0e680;padding: 1.618rem;overflow: auto;}\n.fed-comments.bsky {--ac: #1185fe;}\n.fed-comments.mstd {--ac: #563acc;}\n.fed-comments > header,.fed-comments > footer {display: flex;align-items: center;gap: 1rem;}\n.author img {border-radius: 2rem;}\n.fed-comments > footer {justify-content: space-between;}\n.attachments {display: flex;margin: 1ex 0;overflow: auto;}\n.attachments > *,.attachments img {flex-shrink: 0;width: 100%;height: auto;}\na.date,.stat a {opacity: 0.5;margin: 0 2pt;color: inherit;}\n.stat a.active {opacity: 1;color: var(--ac);}\n.stat .favourites.active {color: red;}\n.has-aria-label::after {display: block;margin: auto;color: #808080;content: attr(aria-label);}\n@font-face {font-family: \'fedi\';\n src: url(data:font/woff2;base64,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);\n}\n.icon,.stat a::before {font-family: \'fedi\';font-style: normal;-moz-font-feature-settings: "liga";-moz-font-feature-settings: "liga=1";-moz-osx-font-smoothing: grayscale;-ms-font-feature-settings: "liga" 1;-webkit-font-feature-settings: "liga";-webkit-font-smoothing: antialiased;-webkit-font-variant-ligatures: discretionary-ligatures;font-feature-settings: "liga";font-variant-ligatures: discretionary-ligatures;}\n.favourites::before {content: "\\e900";}\n.reblogs::before {content: "\\e901";}\n.replies::before {content: "\\e902";}\n.icon.bluesky::before {content: "\\e903";}\n.icon.mastodon::before {content: "\\e904";}\n',document.head.appendChild(cmtSty);const fedRoot=getElement("fed-comments");let replies=0,reblogs=0,favourites=0;const addToCounter=(e,t,n)=>{replies+=e,reblogs+=t,favourites+=n},renderStat=(e,t,n,o)=>`\n <a class='${o} ${e>0?"active":""}' href='${t}' rel='external noreferrer nofollow' aria-label='${n}'>\n <span>${e>0?e:""}</span>\n </a>\n`,respondToVisibility=(e,t)=>{new IntersectionObserver((e=>{e.forEach((e=>{e.isIntersecting&&t()}))})).observe(e)},getURI=(e,t)=>{const n=e.split("/");return"https:"===n[0]||"http:"===n[0]?t(n):e},checkResponseStatus=e=>{if(!e.ok)throw new Error(`HTTP error, status = ${e.status}`)},mstdRoot=getElement("mstd-comments");if(mstdRoot){var mstdCommentsLoaded=!1;const e=mstdRoot.dataset.url,t=e.split("/")[4],n=getURI(e,(e=>`https://${e[2]}/api/v1/statuses/${e[4]}`));if(n!==e){const e=async()=>{if(!mstdCommentsLoaded){fedRoot||(mstdRoot.innerHTML=`<span id=mstdIsLoading class=loading>${i18nLoading}</span>`);try{const[e,a]=await Promise.all([fetch(n),fetch(n+"/context")]),[s,d]=await Promise.all([e.json(),a.json()]);checkResponseStatus(e),checkResponseStatus(a),addToCounter(s.replies_count,s.reblogs_count,s.favourites_count),fedRoot||(getElement("stats").innerHTML=r(s),getElement("mstdIsLoading").remove()),getElement("discussion-starter-content").innerHTML=o(s),replies>0?(mstdRoot.setAttribute("role","feed"),"undefined"!=typeof DOMPurify?DOMPurify.sanitize(i(d.descendants,t),{RETURN_DOM_FRAGMENT:!0}):i(d.descendants,t)):fedRoot||(mstdRoot.innerHTML=i18nNocomment),mstdCommentsLoaded=!0,mstdRoot.setAttribute("aria-busy","false")}catch(e){mstdRoot.innerHTML=`Mastodon ${i18nErr} : ${e}`}}};respondToVisibility(mstdRoot,e)}const o=e=>{const t=e.media_attachments.length>0?`<div class='attachments'>${e.media_attachments.map(a).join("")}</div>`:"";return`\n <div>${e.content}</div>\n ${t}\n `},a=e=>{const t={image:()=>`<a href='${e.url}' rel='nofollow'><img src='${e.preview_url}' alt='${e.description}' loading='lazy' /></a>`,video:()=>`<video controls preload='none'><source src='${e.url}' type='${e.mime_type}'></video>`,gifv:()=>`<video autoplay loop muted playsinline><source src='${e.url}' type='${e.mime_type}'></video>`,audio:()=>`<audio controls><source src='${e.url}' type='${e.mime_type}'></audio>`,default:()=>`<a href='${e.url}' rel='nofollow'>${e.type}</a>`};if(t)return(t[e.type]||t.default)()},r=e=>`\n ${renderStat(e.replies_count,e.url,i18nReplies,"replies")}\n ${renderStat(e.reblogs_count,`${e.url}/reblogs`,i18nReblogs,"reblogs")}\n ${renderStat(e.favourites_count,`${e.url}/favourites`,i18nFavourites,"favourites")}\n `,s=e=>{const t=e=>e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&quot;").replace(/'/g,"&#039;"),n=t(e.account.display_name);e.account.display_name=n,e.account.emojis.forEach((n=>{e.account.display_name=e.account.display_name.replace(`:${n.shortcode}:`,`<img src='${t(n.static_url)}' alt='Emoji ${n.shortcode}' height='20' width='20' />`)}));const a=e=>{let t=`@${e.acct}`;if(!e.acct.includes("@")){t+=`@${new URL(e.url).hostname}`}return t},s=document.createElement("li");return s.id=`mstd${e.id}`,s.dataset.date=toISOString(e.created_at),s.innerHTML=`\n <article class='fed-comments mstd'>\n <header class='author'>\n <img src='${t(e.account.avatar_static)}' height=48 width=48 alt='${a(e.account)}' loading='lazy'/>\n <a class='has-aria-label' href='${e.account.url}' rel='external noreferrer nofollow' aria-label='${a(e.account)}' aria-description='${n}'>\n <span>${e.account.display_name}</span>\n </a>\n </header>\n <div class='content'>${o(e)}</div>\n <footer>\n <div class='stat'>${r(e)}</div>\n <a class='date' href='${e.url}' rel='ugc external noreferrer nofollow'>\n <time datetime='${toISOString(e.created_at)}'>${e.edited_at?"*":""}${formatDate(e.created_at)}</time>\n </a>\n </footer>\n </article>`,s},i=(e,n)=>{e.filter((e=>e.in_reply_to_id===n)).forEach((n=>{if(n.in_reply_to_id===t)fedRoot?fedRoot.appendChild(s(n)):mstdRoot.appendChild(s(n));else{if(e.find((e=>e.id===n.in_reply_to_id))){const e=document.createElement("ul");getElement(`mstd${n.in_reply_to_id}`).appendChild(e).appendChild(s(n))}}i(e,n.id)}))}}const bskyRoot=getElement("bsky-comments");if(bskyRoot){var bskyCommentsLoaded=!1,skeetURL=bskyRoot.dataset.url;const e=e=>{const t=e.split("/");return"at:"===t[0]?"https://bsky.app/profile/"+t[2]+"/post/"+t[4]:e},t=(e,t,n)=>`https://cdn.bsky.app/img/${n?"feed_thumbnail":"feed_fullsize"}/plain/${e}/${t}`,n=getURI(skeetURL,(e=>`at://${e[4]}/app.bsky.feed.post/${e[6]}`));if(n!==skeetURL){const e=async()=>{if(!bskyCommentsLoaded){fedRoot||(bskyRoot.innerHTML=`<span id=bskyIsLoading class=loading>${i18nLoading}</span>`);try{const e=await fetch(`https://public.api.bsky.app/xrpc/app.bsky.feed.getPostThread?uri=${n}`),t=await e.json();if(checkResponseStatus(e),addToCounter(t.thread.post.replyCount,t.thread.post.repostCount,t.thread.post.likeCount),fedRoot||(getElement("stats").innerHTML=s(t.thread.post),getElement("bskyIsLoading").remove()),mstdRoot||(getElement("discussion-starter-content").innerHTML=`<div>${a(t.thread.post.record)}</div>`),replies>0){bskyRoot.setAttribute("role","feed");const e="undefined"!=typeof DOMPurify?DOMPurify.sanitize(d(t.thread),{RETURN_DOM_FRAGMENT:!0}):d(t.thread);if(fedRoot)fedRoot.appendChild(e);else{bskyRoot.appendChild(e);const t=getElements("#bsky-comments > li[data-date]");sortComment(t)}}else fedRoot||(bskyRoot.innerHTML=i18nNocomment);bskyCommentsLoaded=!0,bskyRoot.setAttribute("aria-busy","false")}catch(e){bskyRoot.innerHTML=`Bluesky ${i18nErr} : ${e}`}}};respondToVisibility(bskyRoot,e)}const o=e=>`\n <div>${a(e.record)}</div>\n ${r(e)}\n `,a=e=>{let t="";const n=new TextEncoder,o=new TextDecoder,a=new Uint8Array(3*e.text.length);n.encodeInto(e.text,a);var r=0;for(const n in e.facets){const i=e.facets[n],d=i.features[0],l=d.$type;var s="#";if("app.bsky.richtext.facet#tag"==l?s=`https://bsky.app/hashtag/${d.tag}`:"app.bsky.richtext.facet#link"==l?s=d.uri:"app.bsky.richtext.facet#mention"==l&&(s=`https://bsky.app/profile/${d.did}`),r<i.index.byteStart){const e=a.slice(r,i.index.byteStart);t+=o.decode(e)}const c=a.slice(i.index.byteStart,i.index.byteEnd);t+=`<a href='${s}' target='_blank' rel='external noreferrer nofollow'>`+o.decode(c)+"</a>",r=i.index.byteEnd}if(r<a.length){const e=a.slice(r,a.length);t+=o.decode(e)}return`<p>${t.replace(/\n/g,"<br />")}</p>`},r=e=>{let n="";if(e.embed){const o=e.author.did,a=e.embed.$type;if("app.bsky.embed.external#view"===a){const{uri:t,title:o,description:a,thumb:r}=e.embed.external;t.includes(".gif?")?n=`<img src='${t}' title='${o}' alt='${a}' loading='lazy'>`:r&&(n=`<a href='${t}' aria-label='${o}'><img src='${r}' alt='${a}' loading='lazy'></a>`)}else if("app.bsky.embed.images#view"===a){n=e.record.embed.images.map((e=>{const n=t(o,e.image.ref.$link,!0);return`<a href='${t(o,e.image.ref.$link,!1)}' target='_blank'><img src='${n}' alt='${e.alt}' loading='lazy'></a>`})).join("")}else if("app.bsky.embed.video#view"===a){const t=e.record.embed.video;n=`<video controls poster='${e.embed.thumbnail}' preload='none'><source src='https://bsky.social/xrpc/com.atproto.sync.getBlob?cid=${t.ref.$link}&did=${o}' type='${t.mimeType}'></video>`}return`<div class='attachments'>${n}</div>`}return n},s=t=>`\n ${renderStat(t.replyCount,e(t.uri),i18nReplies,"replies")}\n ${renderStat(t.repostCount,`${e(t.uri)}/reposted-by`,i18nReblogs,"reblogs")}\n ${renderStat(t.likeCount,`${e(t.uri)}/liked-by`,i18nFavourites,"favourites")}\n `,i=t=>{const n=new Date(t.post.record.createdAt);return`\n <li data-date='${toISOString(n)}' id='${t.post.cid}'>\n <article class='fed-comments bsky'>\n <header class='author'>\n <img src='${t.post.author.avatar}' width=48 height=48 alt='${t.post.author.handle}' loading='lazy' />\n <a class='has-aria-label' href='https://bsky.app/profile/${t.post.author.handle}' rel='external noreferrer nofollow' aria-label='@${t.post.author.handle}' aria-description='${t.post.author.displayName}'>\n <span>${t.post.author.displayName}</span>\n </a>\n </header>\n <div class='content'>${o(t.post)}</div>\n <footer>\n <div class='stat'>${s(t.post)}</div>\n <a class='date' href='${e(t.post.uri)}' rel='ugc external noreferrer nofollow'><time datetime='${toISOString(n)}'>${formatDate(n)}</time></a>\n </footer>\n </article>\n </li>`},d=e=>{const t=document.createDocumentFragment(),n=e=>{const t=document.createElement("li");return t.innerHTML=e.trim(),t.firstChild};for(const o of e.replies){const e=n(i(o));if(o.replies.length>0){const t=document.createElement("ul");e.appendChild(t).appendChild(d(o))}t.appendChild(e)}return t}}const sortComment=e=>{const t=Array.from(e),n=new Set;t.sort((({dataset:{date:e}},{dataset:{date:t}})=>e.localeCompare(t))).forEach((e=>{n.has(e.id)?e.remove():(n.add(e.id),e.parentNode.appendChild(e))}))},aggregateComment=()=>{if(mstdCommentsLoaded&&bskyCommentsLoaded){if(replies>0){fedRoot.setAttribute("role","feed");const e=getElements("#fed-comments > li[data-date]");sortComment(e)}else fedRoot.innerHTML=i18nNocomment;getElement("stats").innerHTML=`\n ${renderStat(replies,skeetURL,i18nReplies,"replies")}\n ${renderStat(reblogs,`${skeetURL}/reposted-by`,i18nReblogs,"reblogs")}\n ${renderStat(favourites,`${skeetURL}/liked-by`,i18nFavourites,"favourites")}\n `,bskyRoot.remove(),mstdRoot.remove()}else window.setTimeout(aggregateComment,100)};bskyRoot&&mstdRoot&&aggregateComment(); 1 + const date=new Date,formatDate=e=>new Date(e).toLocaleString("en-US",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:!1,formatMatcher:"basic"}).replace(",","").replace(/(\d+)\/(\d+)\/(\d+)/,"$3-$1-$2"),toISOString=e=>new Date(e).toISOString(),getElement=e=>document.getElementById(e),getElements=e=>document.querySelectorAll(e),cmt=getElement("comments"),{i18nReplies:i18nReplies,i18nReblogs:i18nReblogs,i18nFavourites:i18nFavourites,i18nLoading:i18nLoading,i18nErr:i18nErr,i18nNocomment:i18nNocomment}=cmt.dataset,cmtSty=document.createElement("style");cmtSty.textContent='\n#comments ul {position:relative;padding-left:0;list-style:none;}\n#comments ul::before {position: absolute;top: 0;right: 0;bottom: 0;left: 0;z-index: -1;border-left: 3pt solid #80808008;border-radius: 1ex;content: \'\';}\n#comments ul ul {padding-left: 2em}\n#comments li {padding-top: 2em;list-style: none;}\n.fed-comments {border-left: 3pt solid var(--ac);background: #faf0e680;padding: 1.618rem;overflow: auto;}\n.fed-comments.bsky {--ac: #1185fe;}\n.fed-comments.mstd {--ac: #563acc;}\n.fed-comments > header,.fed-comments > footer {display: flex;align-items: center;gap: 1rem;}\n.author img {border-radius: 2rem;}\n.fed-comments > footer {justify-content: space-between;}\n.attachments {display: flex;margin: 1ex 0;overflow: auto;}\n.attachments > *,.attachments img {flex-shrink: 0;width: 100%;height: auto;}\na.date,.stat a {opacity: 0.5;margin: 0 2pt;color: inherit;}\n.stat a.active {opacity: 1;color: var(--ac);}\n.stat .favourites.active {color: red;}\n.has-aria-label::after {display: block;margin: auto;color: #808080;content: attr(aria-label);}\n@font-face {font-family: \'fedi\';\n src: url(data:font/woff2;base64,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);\n}\n.icon,.stat a::before {font-family: \'fedi\';font-style: normal;-moz-font-feature-settings: "liga";-moz-font-feature-settings: "liga=1";-moz-osx-font-smoothing: grayscale;-ms-font-feature-settings: "liga" 1;-webkit-font-feature-settings: "liga";-webkit-font-smoothing: antialiased;-webkit-font-variant-ligatures: discretionary-ligatures;font-feature-settings: "liga";font-variant-ligatures: discretionary-ligatures;}\n.favourites::before {content: "\\e900";}\n.reblogs::before {content: "\\e901";}\n.replies::before {content: "\\e902";}\n.icon.bluesky::before {content: "\\e903";}\n.icon.mastodon::before {content: "\\e904";}\n',document.head.appendChild(cmtSty);const fedRoot=getElement("fed-comments");let replies=0,reblogs=0,favourites=0;const addToCounter=(e,t,n)=>{replies+=e,reblogs+=t,favourites+=n},renderStat=(e,t,n,o)=>`\n <a class='${o} ${e>0?"active":""}' href='${t}' rel='external noreferrer nofollow' aria-label='${n}'>\n <span>${e>0?e:""}</span>\n </a>\n`,respondToVisibility=(e,t)=>{new IntersectionObserver((e=>{e.forEach((e=>{e.isIntersecting&&t()}))})).observe(e)},getURI=(e,t)=>{const n=e.split("/");return"https:"===n[0]||"http:"===n[0]?t(n):e},checkResponseStatus=e=>{if(!e.ok)throw new Error(`HTTP error, status = ${e.status}`)},mstdRoot=getElement("mstd-comments");if(mstdRoot){var mstdCommentsLoaded=!1;const e=mstdRoot.dataset.url,t=e.split("/")[4],n=getURI(e,(e=>`https://${e[2]}/api/v1/statuses/${e[4]}`));if(n!==e){const e=async()=>{if(!mstdCommentsLoaded){fedRoot||(mstdRoot.innerHTML=`<span id=mstdIsLoading class=loading>${i18nLoading}</span>`);try{const[e,a]=await Promise.all([fetch(n),fetch(n+"/context")]),[r,d]=await Promise.all([e.json(),a.json()]);checkResponseStatus(e),checkResponseStatus(a),addToCounter(r.replies_count,r.reblogs_count,r.favourites_count),fedRoot||(getElement("stats").innerHTML=s(r),getElement("mstdIsLoading").remove()),getElement("discussion-starter-content").innerHTML=o(r),replies>0?(mstdRoot.setAttribute("role","feed"),"undefined"!=typeof DOMPurify?DOMPurify.sanitize(i(d.descendants,t),{RETURN_DOM_FRAGMENT:!0}):i(d.descendants,t)):fedRoot||(mstdRoot.innerHTML=i18nNocomment),mstdCommentsLoaded=!0,mstdRoot.setAttribute("aria-busy","false")}catch(e){mstdRoot.innerHTML=`Mastodon ${i18nErr} : ${e}`}}};respondToVisibility(mstdRoot,e)}const o=e=>{const t=e.media_attachments.length>0?`<div class='attachments'>${e.media_attachments.map(a).join("")}</div>`:"";return`\n <div>${e.content}</div>\n ${t}\n `},a=e=>{const t={image:()=>`<a href='${e.url}' rel='nofollow'><img src='${e.preview_url}' alt='${e.description}' loading='lazy' /></a>`,video:()=>`<video controls preload='none'><source src='${e.url}' type='${e.mime_type}'></video>`,gifv:()=>`<video autoplay loop muted playsinline><source src='${e.url}' type='${e.mime_type}'></video>`,audio:()=>`<audio controls><source src='${e.url}' type='${e.mime_type}'></audio>`,default:()=>`<a href='${e.url}' rel='nofollow'>${e.type}</a>`};if(t)return(t[e.type]||t.default)()},s=e=>`\n ${renderStat(e.replies_count,e.url,i18nReplies,"replies")}\n ${renderStat(e.reblogs_count,`${e.url}/reblogs`,i18nReblogs,"reblogs")}\n ${renderStat(e.favourites_count,`${e.url}/favourites`,i18nFavourites,"favourites")}\n `,r=e=>{const t=e=>e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&quot;").replace(/'/g,"&#039;"),n=t(e.account.display_name);e.account.display_name=n,e.account.emojis.forEach((n=>{e.account.display_name=e.account.display_name.replace(`:${n.shortcode}:`,`<img src='${t(n.static_url)}' alt='Emoji ${n.shortcode}' height='20' width='20' />`)}));const a=e=>{let t=`@${e.acct}`;if(!e.acct.includes("@")){t+=`@${new URL(e.url).hostname}`}return t},r=document.createElement("li");return r.id=`mstd${e.id}`,r.dataset.date=toISOString(e.created_at),r.innerHTML=`\n <article class='fed-comments mstd'>\n <header class='author'>\n <img src='${t(e.account.avatar_static)}' height=48 width=48 alt='${a(e.account)}' loading='lazy'/>\n <a class='has-aria-label' href='${e.account.url}' rel='external noreferrer nofollow' aria-label='${a(e.account)}' aria-description='${n}'>\n <span>${e.account.display_name}</span>\n </a>\n </header>\n <div class='content'>${o(e)}</div>\n <footer>\n <div class='stat'>${s(e)}</div>\n <a class='date' href='${e.url}' rel='ugc external noreferrer nofollow'>\n <time datetime='${toISOString(e.created_at)}'>${e.edited_at?"*":""}${formatDate(e.created_at)}</time>\n </a>\n </footer>\n </article>`,r},i=(e,n)=>{e.filter((e=>e.in_reply_to_id===n)).forEach((n=>{if(n.in_reply_to_id===t)fedRoot?fedRoot.appendChild(r(n)):mstdRoot.appendChild(r(n));else{if(e.find((e=>e.id===n.in_reply_to_id))){const e=document.createElement("ul");getElement(`mstd${n.in_reply_to_id}`).appendChild(e).appendChild(r(n))}}i(e,n.id)}))}}const bskyRoot=getElement("bsky-comments");if(bskyRoot){var bskyCommentsLoaded=!1,skeetURL=bskyRoot.dataset.url;const e=e=>{const t=e.split("/");return"at:"===t[0]?"https://bsky.app/profile/"+t[2]+"/post/"+t[4]:e},t=(e,t,n)=>`https://cdn.bsky.app/img/${n?"feed_thumbnail":"feed_fullsize"}/plain/${e}/${t}`,n=getURI(skeetURL,(e=>`at://${e[4]}/app.bsky.feed.post/${e[6]}`));if(n!==skeetURL){const e=async()=>{if(!bskyCommentsLoaded){fedRoot||(bskyRoot.innerHTML=`<span id=bskyIsLoading class=loading>${i18nLoading}</span>`);try{const e=await fetch(`https://public.api.bsky.app/xrpc/app.bsky.feed.getPostThread?uri=${n}`),t=await e.json();if(checkResponseStatus(e),addToCounter(t.thread.post.replyCount,t.thread.post.repostCount,t.thread.post.likeCount),fedRoot||(getElement("stats").innerHTML=r(t.thread.post),getElement("bskyIsLoading").remove()),mstdRoot||(getElement("discussion-starter-content").innerHTML=`<div>${a(t.thread.post.record)}</div>`),replies>0){bskyRoot.setAttribute("role","feed");const e="undefined"!=typeof DOMPurify?DOMPurify.sanitize(d(t.thread),{RETURN_DOM_FRAGMENT:!0}):d(t.thread);if(fedRoot)fedRoot.appendChild(e);else{bskyRoot.appendChild(e);const t=getElements("#bsky-comments > li[data-date]");sortComment(t)}}else fedRoot||(bskyRoot.innerHTML=i18nNocomment);bskyCommentsLoaded=!0,bskyRoot.setAttribute("aria-busy","false")}catch(e){bskyRoot.innerHTML=`Bluesky ${i18nErr} : ${e}`}}};respondToVisibility(bskyRoot,e)}const o=e=>`\n <div>${a(e.record)}</div>\n ${s(e)}\n `,a=e=>{let t="";const n=new TextEncoder,o=new TextDecoder,a=new Uint8Array(3*e.text.length);n.encodeInto(e.text,a);var s=0;for(const n in e.facets){const i=e.facets[n],d=i.features[0],l=d.$type;var r="#";if("app.bsky.richtext.facet#tag"==l?r=`https://bsky.app/hashtag/${d.tag}`:"app.bsky.richtext.facet#link"==l?r=d.uri:"app.bsky.richtext.facet#mention"==l&&(r=`https://bsky.app/profile/${d.did}`),s<i.index.byteStart){const e=a.slice(s,i.index.byteStart);t+=o.decode(e)}const c=a.slice(i.index.byteStart,i.index.byteEnd);t+=`<a href='${r}' target='_blank' rel='external noreferrer nofollow'>`+o.decode(c)+"</a>",s=i.index.byteEnd}if(s<a.length){const e=a.slice(s,a.length);t+=o.decode(e)}return`<p>${t.replace(/\n/g,"<br />")}</p>`},s=e=>{let n="";if(e.embed){const o=e.author.did,a=e.embed.$type;if("app.bsky.embed.external#view"===a){const{uri:t,title:o,description:a,thumb:s}=e.embed.external;t.includes(".gif?")?n=`<img src='${t}' title='${o}' alt='${a}' loading='lazy'>`:s&&(n=`<a href='${t}' aria-label='${o}'><img src='${s}' alt='${a}' loading='lazy'></a>`)}else if("app.bsky.embed.images#view"===a){n=e.record.embed.images.map((e=>{const n=t(o,e.image.ref.$link,!0);return`<a href='${t(o,e.image.ref.$link,!1)}' target='_blank'><img src='${n}' alt='${e.alt}' loading='lazy'></a>`})).join("")}else if("app.bsky.embed.video#view"===a){const t=e.record.embed.video;n=`<video controls poster='${e.embed.thumbnail}' preload='none'><source src='https://bsky.social/xrpc/com.atproto.sync.getBlob?cid=${t.ref.$link}&did=${o}' type='${t.mimeType}'></video>`}return`<div class='attachments'>${n}</div>`}return n},r=t=>`\n ${renderStat(t.replyCount,e(t.uri),i18nReplies,"replies")}\n ${renderStat(t.repostCount,`${e(t.uri)}/reposted-by`,i18nReblogs,"reblogs")}\n ${renderStat(t.likeCount,`${e(t.uri)}/liked-by`,i18nFavourites,"favourites")}\n `,i=t=>{const n=new Date(t.post.record.createdAt);return`\n <li data-date='${toISOString(n)}' id='${t.post.cid}'>\n <article class='fed-comments bsky'>\n <header class='author'>\n <img src='${t.post.author.avatar}' width=48 height=48 alt='${t.post.author.handle}' loading='lazy' />\n <a class='has-aria-label' href='https://bsky.app/profile/${t.post.author.handle}' rel='external noreferrer nofollow' aria-label='@${t.post.author.handle}' aria-description='${t.post.author.displayName}'>\n <span>${t.post.author.displayName}</span>\n </a>\n </header>\n <div class='content'>${o(t.post)}</div>\n <footer>\n <div class='stat'>${r(t.post)}</div>\n <a class='date' href='${e(t.post.uri)}' rel='ugc external noreferrer nofollow'><time datetime='${toISOString(n)}'>${formatDate(n)}</time></a>\n </footer>\n </article>\n </li>`},d=e=>{const t=document.createDocumentFragment(),n=e=>{const t=document.createElement("li");return t.innerHTML=e.trim(),t.firstChild};for(const o of e.replies){const e=n(i(o));if(o.replies.length>0){const t=document.createElement("ul");e.appendChild(t).appendChild(d(o))}t.appendChild(e)}return t}}const sortComment=e=>{const t=Array.from(e),n=new Set;t.sort((({dataset:{date:e}},{dataset:{date:t}})=>e.localeCompare(t))).forEach((e=>{n.has(e.id)?e.remove():(n.add(e.id),e.parentNode.appendChild(e))}))},aggregateComment=()=>{if(mstdCommentsLoaded&&bskyCommentsLoaded){if(replies>0){fedRoot.setAttribute("role","feed");const e=getElements("#fed-comments > li[data-date]");sortComment(e)}else fedRoot.innerHTML=i18nNocomment;getElement("stats").innerHTML=`\n ${renderStat(replies,skeetURL,i18nReplies,"replies")}\n ${renderStat(reblogs,`${skeetURL}/reposted-by`,i18nReblogs,"reblogs")}\n ${renderStat(favourites,`${skeetURL}/liked-by`,i18nFavourites,"favourites")}\n `,bskyRoot.remove(),mstdRoot.remove()}else window.setTimeout(aggregateComment,100)};bskyRoot&&mstdRoot&&aggregateComment();