Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131// api/playlist, 2025.06.27.12.00// Dynamic playlists of AC pieces conforming to the Feral File DP-1 spec.
export async function handler(event, context) { if (event.httpMethod !== "GET") { return { statusCode: 405, headers: { "Content-Type": "application/json" }, body: JSON.stringify({ error: "Method not allowed" }), }; }
// Parse query params const params = new URLSearchParams(event.rawQuery || ''); const limit = parseInt(params.get('limit')) || 10; const duration = parseInt(params.get('duration')) || 60; // Default 60s per item const density = parseInt(params.get('density')) || 8; const type = params.get('type') || 'kidlisp'; // kidlisp, static, or custom list name const handle = params.get('handle'); // Optional: filter by @handle (with or without @)
// ๐ง Environment detection const dev = process.env.NETLIFY_DEV || process.env.CONTEXT === "dev"; const baseUrl = dev ? "https://local.aesthetic.computer" : "https://aesthetic.computer"; const deviceUrl = dev ? "https://local.aesthetic.computer/device.kidlisp.com" : "https://device.kidlisp.com";
// ๐๏ธ FF DP-1: https://docs.google.com/document/d/1fEB44JTP2_M7ZiP5MR03FKcjNnnH4vTJ5_y-0foE08Q/edit?usp=sharing // ๐ฆ Top-Level (3.1): dpVersion, id, created, defaults?, signature? // ๐ฎ Display (4): scaling, background, margin, autoplay?, loop?, interaction? // ๐ Items[] (3.2): id, title, source, duration?, license?, ref?, override? // ๐ Repro (5): engineVersion?, seed?, assetsSHA256?, frameHash? // ๐ Provenance (6): type, contract?, dependencies? // ๐ Security (7.1): Ed25519 signature // ๐ Transport (8): HTTP, IPFS, offline support
let items = [];
if (type === 'kidlisp') { // Fetch top KidLisp hits from /api/tv try { // Fetch more items when filtering by handle (need full collection) const fetchLimit = handle ? 200 : limit; const tvUrl = `${baseUrl}/api/tv?types=kidlisp&sort=hits&limit=${fetchLimit}`; const response = await fetch(tvUrl); const data = await response.json(); if (data.media && data.media.kidlisp) { let filtered = data.media.kidlisp; // Filter by handle if specified if (handle) { const normalizedHandle = handle.startsWith('@') ? handle : `@${handle}`; filtered = filtered.filter(item => item.owner?.handle?.toLowerCase() === normalizedHandle.toLowerCase() ); } items = filtered .sort((a, b) => (b.hits || 0) - (a.hits || 0)) .slice(0, limit) .map((item, index) => ({ id: `kidlisp-${item.code}`, title: `$${item.code}`, source: `${deviceUrl}/${item.code}?density=${density}&playlist=true&duration=${duration}`, duration: duration, license: "open", provenance: { type: "offChainURI", uri: `${baseUrl}/$${item.code}` } })); } } catch (e) { console.error('Failed to fetch kidlisp hits:', e); } }
// Fallback to static list if dynamic fetch fails or type is 'static' if (items.length === 0 || type === 'static') { items = [ { id: "kidlisp-ceo", title: "$ceo", source: `${deviceUrl}/ceo?density=${density}&playlist=true&duration=${duration}`, duration: duration, license: "open", }, { id: "kidlisp-roz", title: "$roz", source: `${deviceUrl}/roz?density=${density}&playlist=true&duration=${duration}`, duration: duration, license: "open", }, { id: "kidlisp-bels", title: "$bels", source: `${deviceUrl}/bels?density=${density}&playlist=true&duration=${duration}`, duration: duration, license: "open", }, ]; }
// ๐ Build DP-1 playlist const playlistData = { "dpVersion": "1.0.0", "id": `aesthetic-computer-${type}${handle ? `-${handle.replace('@', '')}` : ''}-playlist`, "created": new Date().toISOString(), "defaults": { "display": { "scaling": "fit", "background": "#000000", "margin": "0%" }, "license": "open", "duration": duration }, "items": items, "signature": `aesthetic.computer-${new Date().toISOString().slice(0, 10).replace(/-/g, '.')}` };
return { statusCode: 200, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", "Cache-Control": "public, max-age=300" }, body: JSON.stringify(playlistData, null, 2), };};