// functions/playlist/[id].js class ServerAPI { constructor() { this.INSTANCES_URL = 'https://raw.githubusercontent.com/Monochrome-music/monochrome/main/public/instances.json'; this.apiInstances = null; } async getInstances() { if (this.apiInstances) return this.apiInstances; try { const response = await fetch(this.INSTANCES_URL); if (!response.ok) throw new Error('Failed to fetch instances'); const data = await response.json(); this.apiInstances = data.api || []; return this.apiInstances; } catch (error) { console.error('Failed to load instances:', error); return [ 'https://triton.squid.wtf', 'https://wolf.qqdl.site', 'https://tidal-api.binimum.org', 'https://monochrome-api.samidy.com', ]; } } async fetchWithRetry(relativePath) { const instances = await this.getInstances(); if (instances.length === 0) { throw new Error('No API instances configured.'); } let lastError = null; for (const baseUrl of instances) { const url = baseUrl.endsWith('/') ? `${baseUrl}${relativePath.substring(1)}` : `${baseUrl}${relativePath}`; try { const response = await fetch(url); if (response.ok) { return response; } lastError = new Error(`Request failed with status ${response.status}`); } catch (error) { lastError = error; } } throw lastError || new Error(`All API instances failed for: ${relativePath}`); } async getPlaylistMetadata(id) { try { const response = await this.fetchWithRetry(`/playlist/${id}`); return await response.json(); } catch { // Fallback to query param style const response = await this.fetchWithRetry(`/playlist?id=${id}`); return await response.json(); } } getCoverUrl(id, size = '1080') { if (!id) return ''; const formattedId = id.replace(/-/g, '/'); return `https://resources.tidal.com/images/${formattedId}/${size}x${size}.jpg`; } } export async function onRequest(context) { const { request, params, env } = context; const userAgent = request.headers.get('User-Agent') || ''; const isBot = /discordbot|twitterbot|facebookexternalhit|bingbot|googlebot|slurp|whatsapp|pinterest|slackbot/i.test( userAgent ); const playlistId = params.id; if (isBot && playlistId) { try { const api = new ServerAPI(); const data = await api.getPlaylistMetadata(playlistId); const playlist = data.playlist || data.data || data; if (playlist && (playlist.title || playlist.name)) { const title = playlist.title || playlist.name; const trackCount = playlist.numberOfTracks; const description = `Playlist • ${trackCount} Tracks\nListen on Monochrome`; const imageId = playlist.squareImage || playlist.image; const imageUrl = imageId ? api.getCoverUrl(imageId, '1080') : 'https://monochrome.samidy.com/assets/appicon.png'; const pageUrl = new URL(request.url).href; const metaHtml = `
${description}