// functions/userplaylist/[id].js const POCKETBASE_URL = 'https://data.samidy.xyz'; const PUBLIC_COLLECTION = 'public_playlists'; function safeParseTracks(tracksData) { if (!tracksData) return []; if (Array.isArray(tracksData)) return tracksData; if (typeof tracksData === 'string') { try { return JSON.parse(tracksData); } catch { return []; } } return []; } function parseDuration(durationStr) { if (!durationStr || durationStr === 'N/A' || typeof durationStr !== 'string') return 0; const parts = durationStr.split(':'); if (parts.length === 2) { return parseInt(parts[0]) * 60 + parseInt(parts[1]); } if (parts.length === 3) { return parseInt(parts[0]) * 3600 + parseInt(parts[1]) * 60 + parseInt(parts[2]); } return 0; } function calculatePlaylistDuration(tracks) { let totalSeconds = 0; for (const track of tracks) { const duration = track.duration || track.durationSeconds || 0; if (typeof duration === 'number') { totalSeconds += duration; } else if (typeof duration === 'string') { totalSeconds += parseDuration(duration); } } return totalSeconds; } function formatDuration(seconds) { if (!seconds || seconds <= 0) return '0 min'; const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); if (hours > 0) { return `${hours} hr ${minutes} min`; } return `${minutes} min`; } 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|telegrambot|linkedinbot|mastodon|signal|snapchat|redditbot|skypeuripreview|viberbot|linebot|embedly|quora|outbrain|tumblr|duckduckbot|yandexbot|rogerbot|showyoubot|kakaotalk|naverbot|seznambot|mediapartners|adsbot|petalbot|applebot|ia_archiver/i.test( userAgent ); const playlistId = params.id; if (isBot && playlistId) { try { const filter = `uuid="${playlistId}"`; const apiUrl = `${POCKETBASE_URL}/api/collections/${PUBLIC_COLLECTION}/records?filter=${encodeURIComponent(filter)}&perPage=1`; const response = await fetch(apiUrl); if (!response.ok) throw new Error(`PocketBase error: ${response.status}`); const result = await response.json(); const record = result.items && result.items.length > 0 ? result.items[0] : null; if (record) { let extraData = {}; try { extraData = record.data ? JSON.parse(record.data) : {}; } catch { extraData = {}; } const title = record.title || record.name || (extraData && (extraData.title || extraData.name)) || 'Untitled Playlist'; let tracks = safeParseTracks(record.tracks); const trackCount = tracks.length; const totalDuration = calculatePlaylistDuration(tracks); const durationStr = formatDuration(totalDuration); let rawCover = record.image || record.cover || record.playlist_cover || ''; if (!rawCover && extraData && typeof extraData === 'object') { rawCover = extraData.cover || extraData.image || ''; } let imageUrl = ''; if (rawCover && (rawCover.startsWith('http') || rawCover.startsWith('data:'))) { imageUrl = rawCover; } else if (rawCover) { imageUrl = `${POCKETBASE_URL}/api/files/${PUBLIC_COLLECTION}/${record.id}/${rawCover}`; } if (!imageUrl && tracks.length > 0) { const firstCover = tracks.find((t) => t.album?.cover)?.album?.cover; if (firstCover) { const formattedId = String(firstCover).replace(/-/g, '/'); imageUrl = `https://resources.tidal.com/images/${formattedId}/1080x1080.jpg`; } } if (!imageUrl) { imageUrl = 'https://monochrome.tf/assets/appicon.png'; } const description = `Playlist • ${trackCount} Tracks • ${durationStr}\nListen on Monochrome`; const pageUrl = new URL(request.url).href; const metaHtml = `
${description}