data endpoint for entity 90008 (aka. a website)
at svelte 2.9 kB view raw
1import { env } from '$env/dynamic/private'; 2import { get, writable } from 'svelte/store'; 3 4const DID = 'did:plc:dfl62fgb7wtjj3fcbb72naae'; 5const PDS = 'https://zwsp.xyz'; 6const LAST_TRACK_FILE = `${env.WEBSITE_DATA_DIR}/last_track.json`; 7 8type LastTrack = { 9 name: string; 10 artist: string; 11 album: string; 12 images: { 13 mb: string | null; 14 yt: string | null; 15 }; 16 link: string | null; 17 when: number; 18 status: 'playing' | 'played'; 19}; 20const lastTrack = writable<LastTrack | null>(null); 21 22export const getLastTrack = async () => { 23 try { 24 const data = await Deno.readTextFile(LAST_TRACK_FILE); 25 lastTrack.set(JSON.parse(data)); 26 } catch (why) { 27 console.log('could not read last track: ', why); 28 lastTrack.set(null); 29 } 30}; 31 32const getTrackCoverArt = (releaseMbId: string | null | undefined, originUrl: string | null | undefined) => { 33 let mb: string | null = null; 34 let yt: string | null = null; 35 36 if (releaseMbId) mb = `https://coverartarchive.org/release/${releaseMbId}/front-250`; 37 38 try { 39 if (originUrl) { 40 let videoId: string | null = null; 41 if (originUrl.includes('youtube.com') || originUrl.includes('music.youtube.com')) { 42 videoId = new URL(originUrl).searchParams.get('v'); 43 } else if (originUrl.includes('youtu.be')) { 44 videoId = originUrl.split('youtu.be/')[1]?.split('?')[0]; 45 } 46 if (videoId) yt = `https://img.youtube.com/vi/${videoId}/mqdefault.jpg`; 47 } 48 } catch { 49 } 50 51 return { mb, yt }; 52}; 53 54const joinArtists = (artists: any[]) => { 55 if (!artists || artists.length === 0) return null; 56 return artists.map((a) => a.artistName).join(', '); 57}; 58 59export const updateNowPlayingTrack = async () => { 60 try { 61 let track: any = null; 62 let when: number = Date.now(); 63 let status: 'playing' | 'played' = 'played'; 64 65 try { 66 const statusRes = await fetch( 67 `${PDS}/xrpc/com.atproto.repo.getRecord?repo=${DID}&collection=fm.teal.alpha.actor.status&rkey=self` 68 ); 69 if (statusRes.ok) { 70 const statusData = await statusRes.json(); 71 if (statusData.value?.item) { 72 const metadata = statusData.value; 73 track = statusData.value.item; 74 if (track.playedTime) when = new Date(track.playedTime).getTime(); 75 status = ((Date.now() / 1000) >= (parseInt(metadata.time) + track.duration)) ? 'played' : 'playing'; 76 } 77 } 78 } catch (err) { 79 console.log('could not fetch teal status:', err); 80 } 81 82 if (!track) return; 83 84 const data: LastTrack = { 85 name: track.trackName, 86 artist: joinArtists(track.artists) ?? 'Unknown Artist', 87 album: track.releaseName ?? 'Unknown Album', 88 images: getTrackCoverArt(track.releaseMbId, track.originUrl), 89 link: track.originUrl ?? null, 90 when: when, 91 status: status 92 }; 93 94 lastTrack.set(data); 95 await Deno.writeTextFile(LAST_TRACK_FILE, JSON.stringify(data)); 96 } catch (why) { 97 console.log('could not fetch teal fm: ', why); 98 } 99}; 100 101export const getNowPlayingTrack = () => { 102 return get(lastTrack); 103};