data endpoint for entity 90008 (aka. a website)

fallback to other covers if one is not available

ptr.pet b895d04b 7f61f12b

verified
0/0
Waiting for spindle ...
Changed files
+38 -47
src
lib
routes
(site)
+19 -32
src/lib/lastfm.ts
···
name: string;
artist: string;
album: string;
-
image: string | null;
+
images: {
+
mb: string | null;
+
yt: string | null;
+
};
link: string | null;
when: number;
status: 'playing' | 'played';
···
};
const getTrackCoverArt = (releaseMbId: string | null | undefined, originUrl: string | null | undefined) => {
-
if (releaseMbId) return `https://coverartarchive.org/release/${releaseMbId}/front-250`;
-
-
if (!originUrl) return null;
-
let videoId: string | null = null;
+
let mb: string | null = null;
+
let yt: string | null = null;
+
+
if (releaseMbId) mb = `https://coverartarchive.org/release/${releaseMbId}/front-250`;
try {
-
if (originUrl.includes('youtube.com') || originUrl.includes('music.youtube.com')) {
-
videoId = new URL(originUrl).searchParams.get('v');
-
} else if (originUrl.includes('youtu.be')) {
-
videoId = originUrl.split('youtu.be/')[1]?.split('?')[0];
+
if (originUrl) {
+
let videoId: string | null = null;
+
if (originUrl.includes('youtube.com') || originUrl.includes('music.youtube.com')) {
+
videoId = new URL(originUrl).searchParams.get('v');
+
} else if (originUrl.includes('youtu.be')) {
+
videoId = originUrl.split('youtu.be/')[1]?.split('?')[0];
+
}
+
if (videoId) yt = `https://img.youtube.com/vi/${videoId}/mqdefault.jpg`;
}
} catch {
-
return null;
}
-
if (!videoId) return null;
-
return `https://img.youtube.com/vi/${videoId}/mqdefault.jpg`;
+
return { mb, yt };
};
const joinArtists = (artists: any[]) => {
···
if (statusData.value?.item) {
track = statusData.value.item;
if (track.playedTime) when = new Date(track.playedTime).getTime();
-
status = 'playing';
+
status = (Date.now() / 1000) >= track.expiry ? 'played' : 'playing';
}
}
} catch (err) {
console.log('could not fetch teal status:', err);
}
-
if (!track) {
-
try {
-
const playRes = await fetch(
-
`${PDS}/xrpc/com.atproto.repo.listRecords?repo=${DID}&collection=fm.teal.alpha.feed.play&limit=1`
-
);
-
if (playRes.ok) {
-
const playData = await playRes.json();
-
if (playData.records.length > 0) {
-
track = playData.records[0].value;
-
if (track.playedTime) when = new Date(track.playedTime).getTime();
-
status = 'played';
-
}
-
}
-
} catch (err) {
-
console.log('could not fetch teal history:', err);
-
}
-
}
-
if (!track) return;
const data: LastTrack = {
name: track.trackName,
artist: joinArtists(track.artists) ?? 'Unknown Artist',
album: track.releaseName ?? 'Unknown Album',
-
image: getTrackCoverArt(track.releaseMbId, track.originUrl),
+
images: getTrackCoverArt(track.releaseMbId, track.originUrl),
link: track.originUrl ?? null,
when: when,
status: status
+19 -15
src/routes/(site)/+page.svelte
···
</div>
{/if}
{#if data.lastTrack}
+
{@const images = data.lastTrack.images}
+
{@const initialUrl = images.mb ?? images.yt}
<div class="flex flex-row gap-0.5 m-1.5 border-4 border-double bg-ralsei-black">
<!-- svelte-ignore a11y_missing_attribute -->
-
{#if data.lastTrack.image}
-
<img
-
class="border-4 w-[4.5rem] h-[4.5rem] object-cover"
-
style="border-style: none double none none;"
-
src={data.lastTrack.image}
-
title={data.lastTrack.album}
-
/>
-
{:else}
-
<img
-
class="border-4 w-[4.5rem] h-[4.5rem] p-2"
-
style="border-style: none double none none; image-rendering: pixelated;"
-
src="/icons/cd_audio.webp"
-
title={data.lastTrack.album}
-
/>
-
{/if}
+
<img
+
class="border-4 w-[4.5rem] h-[4.5rem] {initialUrl ? 'object-cover' : 'p-2'}"
+
style="border-style: none double none none; {initialUrl ? '' : 'image-rendering: pixelated;'}"
+
src={initialUrl ?? '/icons/cd_audio.webp'}
+
title={data.lastTrack.album}
+
onerror={(e) => {
+
const img = e.currentTarget as HTMLImageElement;
+
if (images.mb && img.src === images.mb && images.yt)
+
img.src = images.yt;
+
else {
+
img.src = '/icons/cd_audio.webp';
+
img.classList.remove('object-cover');
+
img.classList.add('p-2');
+
img.style.imageRendering = 'pixelated';
+
}
+
}}
+
/>
<div class="flex flex-col max-w-[60ch] p-2">
<p
class="text-shadow-green text-ralsei-green-light text-sm text-ellipsis text-nowrap overflow-hidden max-w-[50ch]"