Something went wrong. Try again.
My website, danielmorrisey.com. Written in HTML, CSS and javascript, by hand. danielmorrisey.com
javascript html css wisp-place
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697document.addEventListener('DOMContentLoaded', () => { const AT_DID = 'did:plc:l37td5yhxl2irrzrgvei4qay';
// ── Music ──────────────────────────────────────────────────────────────
async function fetchMusicStatus() { const url = `https://eurosky.social/xrpc/com.atproto.repo.getRecord?repo=${AT_DID}&collection=fm.teal.alpha.actor.status&rkey=self`; const el = document.getElementById('music-content'); try { const res = await fetch(url); if (!res.ok) throw new Error(res.status); const data = await res.json(); const item = data?.value?.item; if (!item) throw new Error('no item');
const artists = item.artists.map(a => a.artistName).join(', '); const trackUrl = item.originUrl || '#';
el.innerHTML = ` <a href="${trackUrl}" target="_blank" rel="noopener noreferrer" class="track-name">${escapeHtml(item.trackName)}</a> <span class="track-artist">by ${escapeHtml(artists)}</span> `; } catch { el.innerHTML = '<span class="loading-text">no recent activity</span>'; } }
// ── Latest original post ─────────────────────────────────────────────── // filter=posts_no_replies strips replies from the API response. // We then skip any reposts (reason.$type === reasonRepost) client-side, // since the filter param doesn't exclude those.
async function fetchLatestPost() { // Fetch a small batch so we can skip any leading reposts const url = `https://public.api.bsky.app/xrpc/app.bsky.feed.getAuthorFeed?actor=${AT_DID}&limit=10&filter=posts_no_replies`; const contentEl = document.getElementById('post-content'); const dateEl = document.getElementById('post-date'); const mediaEl = document.getElementById('post-media'); try { const res = await fetch(url); if (!res.ok) throw new Error(res.status); const data = await res.json();
// Find first item that is neither a reply nor a repost const item = (data.feed || []).find(entry => !entry.reason && // no repost reason !entry.post.record.reply // no reply parent );
if (!item) throw new Error('no original posts found');
const post = item.post; const record = post.record; const rkey = post.uri.split('/').pop(); const postUrl = `https://bsky.app/profile/danielmorrisey.com/post/${rkey}`;
contentEl.innerHTML = ` <p>${escapeHtml(record.text || '')}</p> <a href="${postUrl}" target="_blank" rel="noopener noreferrer" style="font-size:0.8125rem;opacity:0.6;">view on Bluesky</a> `;
if (record.createdAt) { dateEl.textContent = new Date(record.createdAt).toLocaleDateString('en-GB', { day: 'numeric', month: 'long', year: 'numeric' }); }
// Images if (record.embed?.$type === 'app.bsky.embed.images') { record.embed.images.forEach(img => { const ref = img.image.ref.$link; const src = `https://imrs.danielmorrisey.com/https://luna.danielmorrisey.com/img/feed_fullsize/plain/${AT_DID}/${ref}@jpeg`; const el = document.createElement('img'); el.src = src; el.alt = img.alt || 'error: image failed to load, failed to reach luna.danielmorrisey.com and/or imrs.danielmorrisey.com'; el.loading = 'lazy'; mediaEl.appendChild(el); }); } } catch { contentEl.innerHTML = '<span class="loading-text">couldn\'t load post</span>'; } }
// ── Helpers ────────────────────────────────────────────────────────────
function escapeHtml(str) { return str .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"'); }
fetchMusicStatus(); fetchLatestPost();});