// -------------------------------------------------------- // DATEN AUS DEN VORHERIGEN NODES HOLEN // -------------------------------------------------------- // 1. Spotify Node let spotifyData = null; try { spotifyData = $('Spotify').first().json; } catch (e) {} // 2. Lanyard Node (Discord) let lanyardData = null; try { lanyardData = $('Lanyard').first().json.data; } catch (e) {} // 3. Wakapi Summary (Tages-Statistik) let wakapiStats = null; try { const wRaw = $('Wakapi').first().json; // Manchmal ist es direkt im Root, manchmal unter data wakapiStats = wRaw.grand_total ? wRaw : (wRaw.data ? wRaw.data : null); } catch (e) {} // 4. Wakapi Heartbeats (Live Check) let heartbeatsList = []; try { const response = $('WakapiLast').last().json; if (response.data && Array.isArray(response.data)) { heartbeatsList = response.data; } } catch (e) {} // 5. Hardcover Reading (Neu!) let hardcoverData = null; try { // Falls du einen Node "Hardcover" hast hardcoverData = $('Hardcover').first().json; } catch (e) {} // -------------------------------------------------------- // LOGIK & FORMATIERUNG // -------------------------------------------------------- // --- A. SPOTIFY / MUSIC --- let music = null; if (spotifyData && spotifyData.item && spotifyData.is_playing) { music = { isPlaying: true, track: spotifyData.item.name, artist: spotifyData.item.artists.map(a => a.name).join(', '), album: spotifyData.item.album.name, albumArt: spotifyData.item.album.images[0]?.url, url: spotifyData.item.external_urls.spotify }; } else if (lanyardData?.listening_to_spotify && lanyardData.spotify) { music = { isPlaying: true, track: lanyardData.spotify.song, artist: lanyardData.spotify.artist.replace(/;/g, ", "), album: lanyardData.spotify.album, albumArt: lanyardData.spotify.album_art_url, url: `https://open.spotify.com/track/${lanyardData.spotify.track_id}` }; } // --- B. GAMING & STATUS --- let gaming = null; let status = { text: lanyardData?.discord_status || "offline", color: 'gray' }; // Farben mapping if (status.text === 'online') status.color = 'green'; if (status.text === 'idle') status.color = 'yellow'; if (status.text === 'dnd') status.color = 'red'; if (lanyardData?.activities) { lanyardData.activities.forEach(act => { // Type 0 = Game (Spotify ignorieren) if (act.type === 0 && act.name !== "Spotify") { let image = null; if (act.assets?.large_image) { if (act.assets.large_image.startsWith("mp:external")) { image = act.assets.large_image.replace(/mp:external\/([^\/]*)\/(https?)\/(^\/]*)\/(.*)/,"$2://$3/$4"); } else { image = `https://cdn.discordapp.com/app-assets/${act.application_id}/${act.assets.large_image}.png`; } } gaming = { isPlaying: true, name: act.name, details: act.details, state: act.state, image: image }; } }); } // --- C. CODING (Wakapi Logic) --- let coding = null; // 1. Basis-Stats von heute (Fallback) if (wakapiStats && wakapiStats.grand_total) { coding = { isActive: false, stats: { time: wakapiStats.grand_total.text, topLang: wakapiStats.languages?.[0]?.name || "Code", topProject: wakapiStats.projects?.[0]?.name || "Project" } }; } // 2. Live Check via Heartbeats if (heartbeatsList.length > 0) { const latestBeat = heartbeatsList[heartbeatsList.length - 1]; if (latestBeat && latestBeat.time) { const beatTime = new Date(latestBeat.time * 1000).getTime(); const now = new Date().getTime(); const diffMinutes = (now - beatTime) / 1000 / 60; // Wenn jünger als 15 Minuten -> AKTIV if (diffMinutes < 15) { if (!coding) coding = { stats: { time: "Just started" } }; coding.isActive = true; coding.project = latestBeat.project || coding.stats?.topProject; if (latestBeat.entity) { const parts = latestBeat.entity.split(/[/\\]/); coding.file = parts[parts.length - 1]; } coding.language = latestBeat.language; } } } // --- D. CUSTOM ACTIVITIES (Komplett dynamisch!) --- // Hier kannst du beliebige Activities hinzufügen ohne Website Code zu ändern let customActivities = {}; // Beispiel: Reading Activity (Hardcover Integration) if (hardcoverData && hardcoverData.user_book) { const book = hardcoverData.user_book; customActivities.reading = { enabled: true, title: book.book?.title, author: book.book?.contributions?.[0]?.author?.name, progress: book.progress_pages && book.book?.pages ? Math.round((book.progress_pages / book.book.pages) * 100) : undefined, coverUrl: book.book?.image_url }; } // Beispiel: Manuell gesetzt via separatem Webhook // Du kannst einen Webhook erstellen der customActivities setzt: // POST /webhook/set-custom-activity // { // "type": "working_out", // "data": { // "enabled": true, // "activity": "Running", // "duration_minutes": 45, // "distance_km": 7.2, // "calories": 350 // } // } // Dann hier einfach: customActivities.working_out = $('SetCustomActivity').first().json.data; // WICHTIG: Du kannst auch mehrere Activities gleichzeitig haben! // customActivities.learning = { enabled: true, course: "Docker", platform: "Udemy", progress: 67 }; // customActivities.streaming = { enabled: true, platform: "Twitch", viewers: 42 }; // etc. // -------------------------------------------------------- // OUTPUT // -------------------------------------------------------- return { json: { status, music, gaming, coding, customActivities, // NEU! Komplett dynamisch timestamp: new Date().toISOString() } };