feat(web+android+backend): Konzerte gefolgter Kuenstler als zweiter Reiter

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-09-25 19:23:00 +02:00
1 parent 1366ec3832
commit 17a677a5a5
13 files changed
+682 -14

No files matched your search

+26
View File
@@ -256,6 +256,32 @@ app.post('/api/artist-releases', async (req, res) => {
}
});
// POST /api/artist-concerts { artists: [{id, name}], days }
// Gegenstueck zu /api/artist-releases: anstehende Termine aller gefolgten Kuenstler.
// Ohne Ortsfilter — Ticketmaster sucht weltweit. Das ist bewusst so (siehe CHANGELOG-Backlog):
// eine Einschraenkung per .env kommt spaeter, fuers Erste reicht, was die API liefert.
app.post('/api/artist-concerts', async (req, res) => {
const key = CONFIG.ticketmasterKey;
if (!key) return res.json({ konzerte: [], ohneTermine: [], keinSchluessel: true });
const artists = Array.isArray(req.body?.artists) ? req.body.artists : [];
const days = Math.min(Math.max(parseInt(req.body?.days, 10) || 365, 1), 365);
if (!artists.length) return res.json({ konzerte: [], ohneTermine: [] });
// Obergrenze, damit ein kaputter Client nicht hunderte Ticketmaster-Aufrufe ausloest.
if (artists.length > 300) return res.status(400).json({ error: 'Zu viele Künstler (max. 300)' });
const sauber = artists.filter(a => a && a.id && a.name)
.map(a => ({ id: String(a.id), name: String(a.name) }));
try {
const { kommendeKonzerte } = require('./lib/konzerte');
res.json(await kommendeKonzerte(sauber, key, days));
} catch (e) {
console.error('[concerts]', e.message);
res.status(502).json({ error: e.message });
}
});
// DELETE /api/artist-overrides/:ndArtistId — remove a pin
app.delete('/api/artist-overrides/:ndArtistId', (req, res) => {
const id = decodeURIComponent(req.params.ndArtistId);