Personal Site
0
fork

Configure Feed

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

Create server sent events to update clients of new songs.

Potential for performance improvements by increasing delay between requests and sharing a stream between multiple clients but 1 i dont wanna do that and 2 its prolly fine for now lol

+68
+68
src/pages/now-playing-sse.ts
··· 1 + import { nowPlaying } from "/components/playing/spotify"; 2 + 3 + export async function GET() { 4 + const update = async (): Promise<string> => { 5 + // extract a subset to reduce size for client 6 + // not huge savings but tesco yk 7 + const playing = await nowPlaying().then((playing) => 8 + playing 9 + ? { 10 + type: "track", 11 + id: playing.id, 12 + name: playing.name, 13 + album: { 14 + images: playing.album.images.map((x) => ({ 15 + url: x.url, 16 + width: x.width, 17 + height: x.height, 18 + })), 19 + }, 20 + artists: playing.artists.map((x) => ({ 21 + name: x.name, 22 + id: x.id, 23 + })), 24 + } 25 + : null, 26 + ); 27 + 28 + // SSE syntax: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#event_stream_format 29 + return `event: playing\ndata: ${JSON.stringify(playing)}\n\n`; 30 + }; 31 + 32 + const abort = new AbortController(); 33 + 34 + return new Response( 35 + new ReadableStream({ 36 + async start(controller) { 37 + while (!abort.signal.aborted) { 38 + // dont block loop if spotify API is slow/etc 39 + update() 40 + // dont write if aborted as it can cause errors 41 + .then((val) => 42 + !abort.signal.aborted ? controller.enqueue(val) : undefined, 43 + ) 44 + .catch((err) => { 45 + console.error("GOT ERROR:", err); 46 + }); 47 + await new Promise((res, rej) => { 48 + setTimeout(res, 5000); 49 + abort.signal.addEventListener("abort", rej); 50 + }); 51 + } 52 + }, 53 + 54 + async cancel() { 55 + abort.abort(); 56 + }, 57 + }), 58 + { 59 + // Set the headers for Server-Sent Events (SSE) 60 + headers: { 61 + Connection: "keep-alive", 62 + "Content-Encoding": "none", 63 + "Cache-Control": "no-cache, no-transform", 64 + "Content-Type": "text/event-stream; charset=utf-8", 65 + }, 66 + }, 67 + ); 68 + }