diff --git a/backend/novasonic-server.js b/backend/novasonic-server.js index 0a41b80..4029fba 100644 --- a/backend/novasonic-server.js +++ b/backend/novasonic-server.js @@ -315,6 +315,20 @@ app.get('/api/itunes/:endpoint', (req, res) => { }).on('error', e => res.status(502).json({ error: e.message })); }); +app.get('/api/events/:artist', (req, res) => { + const artist = req.params.artist; + const target = `https://rest.bandsintown.com/artists/${encodeURIComponent(artist)}/events?app_id=novasonic`; + https.get(target, { + headers: { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', + 'Accept': 'application/json', + } + }, upstream => { + res.setHeader('Content-Type', 'application/json'); + upstream.pipe(res); + }).on('error', e => res.status(502).json({ error: e.message })); +}); + app.get('/api/health', (req, res) => { res.json({ status: 'ok', ytdlpVersion, diff --git a/src/views/events.js b/src/views/events.js index b06a4ad..c4b4e81 100644 --- a/src/views/events.js +++ b/src/views/events.js @@ -1,8 +1,11 @@ import { esc } from '../utils.js'; +import { S } from '../state.js'; export async function fetchEvents(artistName) { + const base = S.cfg?.backendUrl; + if(!base) return []; try { - const r = await fetch(`https://rest.bandsintown.com/artists/${encodeURIComponent(artistName)}/events?app_id=novasonic`); + const r = await fetch(`${base}/api/events/${encodeURIComponent(artistName)}`); if(!r.ok) return []; const data = await r.json(); if(!Array.isArray(data)) return []; @@ -31,7 +34,7 @@ export function openEventsModal(events, artistName) {
${esc(venue)}
${esc(city)}
- ${offer ? `${soldOut ? 'Ausverkauft' : 'Buchen →'}` : ''} + ${offer ? `${soldOut ? 'Ausverkauft' : ''}Tickets →` : ''} `; }).join(''); diff --git a/styles.css b/styles.css index 149cb17..aa4e76a 100644 --- a/styles.css +++ b/styles.css @@ -855,9 +855,9 @@ button:focus{outline:none} .event-venue{flex:1;min-width:0} .event-venue-name{font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .event-venue-city{font-size:11px;color:var(--text2);margin-top:2px} -.event-book-btn{flex-shrink:0;padding:7px 14px;border-radius:20px;background:var(--accent);color:#fff;font-family:var(--font);font-size:12px;font-weight:700;text-decoration:none;transition:opacity .15s} +.event-book-btn{flex-shrink:0;padding:7px 14px;border-radius:20px;background:var(--accent);color:#fff;font-family:var(--font);font-size:12px;font-weight:700;text-decoration:none;transition:opacity .15s;display:flex;flex-direction:column;align-items:center;gap:2px} .event-book-btn:hover{opacity:.85} -.event-book-btn.sold-out{background:var(--surface2);color:var(--text3)} +.event-sold-badge{font-size:9px;font-weight:600;opacity:.8;letter-spacing:.3px} /* ── MISC ── */ .spinner{width:28px;height:28px;border:3px solid var(--surface2);border-top-color:var(--accent);border-radius:50%;animation:spin .8s linear infinite;margin:50px auto;display:block}