// Wochen-Rückblick: sonntags 20:00 (Container-TZ, siehe compose) postet der Bot // eine Zusammenfassung der Woche in den Devlog-Kanal. import { EmbedBuilder } from 'discord.js'; import { weeklyStats, getSetting, setSetting } from '../db.js'; import { devlogChannelId, publicUrl, brandColor, brandFooter } from '../runtime-settings.js'; import { config } from '../config.js'; import { moduleEnabled } from '../modules.js'; import { tuning } from '../tuning.js'; const CHECK_INTERVAL_MS = 5 * 60 * 1000; /** Balken-Zeile: `Mo 21.07 ████████ 12` */ function buildBars(perDay) { const byDay = new Map(perDay.map((r) => [r.day, r.n])); const rows = []; let max = 1; // Letzte 7 Tage, älteste zuerst for (let i = 6; i >= 0; i--) { const date = new Date(Date.now() - i * 86400000); const key = date.toISOString().slice(0, 10); const n = byDay.get(key) ?? 0; max = Math.max(max, n); rows.push({ date, n }); } const dayFmt = new Intl.DateTimeFormat('de-DE', { weekday: 'short' }); const dateFmt = new Intl.DateTimeFormat('de-DE', { day: '2-digit', month: '2-digit' }); return rows .map((r) => { const bar = '█'.repeat(Math.round((r.n / max) * 14)) || '·'; return `${dayFmt.format(r.date).padEnd(3)}${dateFmt.format(r.date)} ${bar} ${r.n}`; }) .join('\n'); } /** Rückblick-Embed bauen und in den Devlog-Kanal posten */ export async function postWeeklyRecap(client) { if (!moduleEnabled('weekly_recap')) return; const channelId = devlogChannelId(); if (!channelId) throw new Error('Kein Devlog-Kanal konfiguriert'); const channel = await client.channels.fetch(channelId); if (!channel?.isTextBased()) throw new Error('Devlog-Kanal nicht gefunden'); const stats = weeklyStats(); const totalCommits = stats.perDay.reduce((sum, r) => sum + r.n, 0); const repoLine = stats.topRepos .map((r) => `**${r.repo.split('/').pop()}** (${r.n})`) .join(' · '); const embed = new EmbedBuilder() .setColor(brandColor()) .setTitle('📊 Wochen-Rückblick') .setURL(`${publicUrl()}/devlogs`) .setDescription( `\`\`\`\n${buildBars(stats.perDay)}\n\`\`\`` ) .addFields( { name: 'Commits', value: String(totalCommits), inline: true }, { name: 'Devlogs', value: String(stats.devlogs), inline: true }, ...(repoLine ? [{ name: 'Aktive Projekte', value: repoLine, inline: false }] : []) ) .setFooter({ text: brandFooter('WEEKLY'), iconURL: client?.user?.displayAvatarURL?.({ size: 64 }) }) .setTimestamp(); await channel.send({ embeds: [embed] }); } /** Scheduler starten: prüft alle 5 Minuten, ob Sonntag ≥ 20:00 und noch nicht gepostet */ export function scheduleWeeklyRecap(client) { const check = async () => { if (getSetting('weekly_recap_enabled') === '0') return; const now = new Date(); // Wochentag und Uhrzeit kommen aus den Stellwerten (lokale TZ des Containers) if (now.getDay() !== tuning('recap_weekday') || now.getHours() < tuning('recap_hour')) return; const today = now.toISOString().slice(0, 10); if (getSetting('last_weekly_recap') === today) return; try { await postWeeklyRecap(client); setSetting('last_weekly_recap', today); console.log('[weekly] Wochen-Rückblick gepostet'); } catch (error) { console.error('[weekly] Rückblick fehlgeschlagen:', error); } }; setInterval(check, CHECK_INTERVAL_MS); check(); }