the home site for me: also iteration 3 or 4 of my site
at main 79 lines 3.3 kB view raw
1{% if config.extra.header_nav %} 2{% if page %} 3{% set active_path = page.path | trim_end_matches(pat="/") %} 4{% elif section %} 5{% set active_path = section.path | trim_end_matches(pat="/") %} 6{% elif current_path %} 7{% set active_path = current_path | trim_end_matches(pat="/") %} 8{% else %} 9{% set active_path = "" %} 10{% endif %} 11<div id="header-container"> 12 <span id="now-playing"></span> 13 <nav id="nav-bar"> 14 {% for nav_item in config.extra.header_nav %} 15 <a href="{{ nav_item.url }}" 16 class="{% if nav_item.url == active_path or (nav_item.url == '/' and active_path == '') %}active{% endif %}"> 17 {{ nav_item.name }} 18 </a> 19 {% endfor %} 20 </nav> 21</div> 22<script> 23 async function resolveDidToPds(did) { 24 if (did.startsWith("did:plc:")) { 25 const res = await fetch(`https://plc.directory/${did}`); 26 const doc = await res.json(); 27 return doc.service?.find(s => s.id === "#atproto_pds")?.serviceEndpoint; 28 } else if (did.startsWith("did:web:")) { 29 const domain = did.slice(8); 30 const res = await fetch(`https://${domain}/.well-known/did.json`); 31 const doc = await res.json(); 32 return doc.service?.find(s => s.id === "#atproto_pds")?.serviceEndpoint; 33 } 34 return null; 35 } 36 async function fetchAtUriRecord(atUri) { 37 const match = atUri.match(/^at:\/\/([^/]+)\/([^/]+)\/([^/]+)$/); 38 if (!match) return null; 39 const [, repo, collection, rkey] = match; 40 const pds = await resolveDidToPds(repo); 41 if (!pds) return null; 42 const url = `${pds}/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(repo)}&collection=${encodeURIComponent(collection)}&rkey=${encodeURIComponent(rkey)}`; 43 const res = await fetch(url); 44 return res.ok ? res.json() : null; 45 } 46 let nowPlayingTimeout = null; 47 function fetchNowPlaying() { 48 if (nowPlayingTimeout) clearTimeout(nowPlayingTimeout); 49 fetchAtUriRecord("at://did:plc:krxbvxvis5skq7jj6eot23ul/fm.teal.alpha.actor.status/self") 50 .then((data) => { 51 const el = document.getElementById("now-playing"); 52 if (!data?.value?.item) { 53 el.innerHTML = ""; 54 nowPlayingTimeout = setTimeout(fetchNowPlaying, 60000); 55 return; 56 } 57 const item = data.value.item; 58 const expiry = new Date(data.value.expiry).getTime(); 59 const now = Date.now(); 60 if (now > expiry) { 61 el.innerHTML = ""; 62 nowPlayingTimeout = setTimeout(fetchNowPlaying, 60000); 63 return; 64 } 65 el.innerHTML = ` 66 <div class="now-playing-line"><span>🎵</span><a href="${item.originUrl || '#'}" target="_blank" rel="noopener"><span class="track-name">${item.trackName}</span></a></div> 67 <div class="now-playing-line artist-line">${item.artists?.[0]?.artistName || 'Unknown'}</div> 68 <div class="now-playing-line"><relative-time datetime="${item.playedTime}" threshold="P1D"></relative-time></div> 69 `; 70 const timeUntilExpiry = expiry - now + 5000; 71 nowPlayingTimeout = setTimeout(fetchNowPlaying, timeUntilExpiry); 72 }) 73 .catch(() => { 74 nowPlayingTimeout = setTimeout(fetchNowPlaying, 60000); 75 }); 76 } 77 document.addEventListener("DOMContentLoaded", fetchNowPlaying); 78</script> 79{% endif %}