Devlog-Embed aufgehübscht: Datum im Titel, Author-Zeile, Footer-Commits, Link-Buttons

- Titel: '📔 Devlog — <Wochentag, Datum>' statt 'Devlog — Repo'
- Projekt als Author-Zeile mit Bot-Avatar
- Commit-Fußzeile aus der Prosa geparst → in den Footer verschoben
- Link-Buttons unterm Embed: Devlog-Archiv + Repo
- Archiv-Format unverändert (Webseite kompatibel)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 10:30:29 +02:00
co-authored by Claude Opus 4.8
parent ae5732a61b
commit f2cae33b8f
+47 -12
View File
@@ -7,7 +7,7 @@
import crypto from 'node:crypto';
import { writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import { AttachmentBuilder, EmbedBuilder } from 'discord.js';
import { ActionRowBuilder, AttachmentBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from 'discord.js';
import { config } from '../config.js';
import { saveDevlog } from '../db.js';
import { devlogChannelId } from '../runtime-settings.js';
@@ -65,6 +65,21 @@ export function registerDevlogEndpoint(app, client) {
return reply.code(400).send({ error: 'empty devlog' });
}
// devlog.py-Payload zerlegen: Projekt aus dem Titel („Devlog — X"),
// Commit-Fußzeile („*N Commits heute — Details im [Repo](url)*") aus der Prosa
const project = title.match(/^Devlog\s*[—–-]\s*(.+)$/i)?.[1]?.trim() ?? null;
const blocks = description.trim().split(/\n{2,}/);
let prose = description.trim();
let commitCount = null;
let repoUrl = srcEmbed.url || null;
const lastBlock = blocks[blocks.length - 1]?.trim() ?? '';
const footerMatch = lastBlock.match(/^\*(\d+)\s+Commits?[^*]*\*$/s);
if (blocks.length > 1 && footerMatch) {
commitCount = Number(footerMatch[1]);
repoUrl = lastBlock.match(/\[Repo\]\((https?:[^\s)]+)\)/)?.[1] ?? repoUrl;
prose = blocks.slice(0, -1).join('\n\n');
}
const targetChannel = devlogChannelId();
if (!targetChannel) {
return reply.code(500).send({ error: 'no devlog channel configured' });
@@ -75,19 +90,29 @@ export function registerDevlogEndpoint(app, client) {
}
// Gebrandetes Embed; bis zu 4 Bilder als Grid (Discord gruppiert Embeds mit gleicher URL)
const groupUrl = srcEmbed.url || `${config.publicUrl}/devlogs`;
const groupUrl = `${config.publicUrl}/devlogs`;
const dateStr = new Intl.DateTimeFormat('de-DE', {
weekday: 'long', day: 'numeric', month: 'long', year: 'numeric',
}).format(new Date());
const attachments = files.map(
(f, i) => new AttachmentBuilder(f.buffer, { name: `devlog_${i}.${f.name.split('.').pop().toLowerCase()}` })
);
const embeds = [
new EmbedBuilder()
.setColor(BRAND_YELLOW)
.setTitle(title)
.setURL(groupUrl)
.setDescription(description)
.setFooter({ text: 'D4RKST3R // DEVLOG' })
.setTimestamp(),
];
const mainEmbed = new EmbedBuilder()
.setColor(BRAND_YELLOW)
.setTitle(`📔 Devlog — ${dateStr}`)
.setURL(groupUrl)
.setDescription(prose)
.setFooter({
text: `D4RKST3R // DEVLOG${commitCount ? `${commitCount} Commits` : ''}`,
})
.setTimestamp();
if (project) {
mainEmbed.setAuthor({
name: project,
iconURL: client.user?.displayAvatarURL?.() ?? undefined,
});
}
const embeds = [mainEmbed];
attachments.forEach((att, i) => {
if (i === 0) {
embeds[0].setImage(`attachment://${att.name}`);
@@ -98,7 +123,17 @@ export function registerDevlogEndpoint(app, client) {
}
});
const message = await channel.send({ embeds, files: attachments });
// Link-Buttons unterm Embed: Archiv-Seite + Repo
const buttons = new ActionRowBuilder().addComponents(
new ButtonBuilder().setStyle(ButtonStyle.Link).setLabel('Devlog-Archiv').setEmoji('🗂️').setURL(groupUrl)
);
if (repoUrl) {
buttons.addComponents(
new ButtonBuilder().setStyle(ButtonStyle.Link).setLabel('Repo').setEmoji('⚙️').setURL(repoUrl)
);
}
const message = await channel.send({ embeds, files: attachments, components: [buttons] });
// Direkt archivieren (der Live-Listener ignoriert eigene Bot-Posts bewusst)
const imageFiles = [];