Files
portfolio/scripts/n8n-workflow-code-updated.js
denshooter e431ff50fc feat: Add Directus setup scripts for collections, fields, and relations
- Created setup-directus-collections.js to automate the creation of tech stack collections, fields, and relations in Directus.
- Created setup-directus-hobbies.js for setting up hobbies collection with translations.
- Created setup-directus-projects.js for establishing projects collection with comprehensive fields and translations.
- Added setup-tech-stack-directus.js to populate tech_stack_items with predefined data.
2026-01-23 02:53:31 +01:00

198 lines
5.7 KiB
JavaScript

// --------------------------------------------------------
// 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()
}
};