Feat: Now-Playing serverseitig syncen + in Topbar verschieben
Backend:
- nowPlaying Map trackt aktuell gespielten Sound pro Guild
- SSE broadcast { type: 'nowplaying' } bei play und stop
- nowplaying im SSE-Snapshot für neue Clients
- playFilePath Helper broadcastet ebenfalls (Party Mode)
Frontend:
- SSE-Handler für nowplaying Events (sync über alle Clients)
- Now-Playing als Pill-Badge in der Topbar (rechts, neben Channel)
- Bottombar komplett entfernt
- Fade-in Animation und accent-farbige Pill
- --accent-rgb CSS Variable für alle Themes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4661c366fb
commit
f90401a009
3 changed files with 58 additions and 46 deletions
|
|
@ -164,6 +164,8 @@ const guildAudioState = new Map<string, GuildAudioState>();
|
|||
// Partymode: serverseitige Steuerung (global pro Guild)
|
||||
const partyTimers = new Map<string, NodeJS.Timeout>();
|
||||
const partyActive = new Set<string>();
|
||||
// Now-Playing: aktuell gespielter Sound pro Guild
|
||||
const nowPlaying = new Map<string, string>();
|
||||
// SSE-Klienten für Broadcasts (z.B. Partymode Status)
|
||||
const sseClients = new Set<Response>();
|
||||
function sseBroadcast(payload: any) {
|
||||
|
|
@ -265,6 +267,10 @@ async function playFilePath(guildId: string, channelId: string, filePath: string
|
|||
state.player.play(resource);
|
||||
state.currentResource = resource;
|
||||
state.currentVolume = useVolume;
|
||||
// Now-Playing broadcast
|
||||
const soundLabel = relativeKey ? path.parse(relativeKey).name : path.parse(filePath).name;
|
||||
nowPlaying.set(guildId, soundLabel);
|
||||
sseBroadcast({ type: 'nowplaying', guildId, name: soundLabel });
|
||||
if (relativeKey) incrementPlaysFor(relativeKey);
|
||||
}
|
||||
|
||||
|
|
@ -1080,6 +1086,9 @@ app.post('/api/play', async (req: Request, res: Response) => {
|
|||
persistedState.volumes[guildId] = volumeToUse;
|
||||
writePersistedState(persistedState);
|
||||
console.log(`${new Date().toISOString()} | player.play() called for ${soundName}`);
|
||||
// Now-Playing broadcast
|
||||
nowPlaying.set(guildId!, soundName!);
|
||||
sseBroadcast({ type: 'nowplaying', guildId, name: soundName });
|
||||
// Plays zählen (relativer Key verfügbar?)
|
||||
if (relativePath) incrementPlaysFor(relativePath);
|
||||
return res.json({ ok: true });
|
||||
|
|
@ -1139,6 +1148,9 @@ app.post('/api/stop', (req: Request, res: Response) => {
|
|||
const state = guildAudioState.get(guildId);
|
||||
if (!state) return res.status(404).json({ error: 'Kein aktiver Player' });
|
||||
state.player.stop(true);
|
||||
// Now-Playing löschen
|
||||
nowPlaying.delete(guildId);
|
||||
sseBroadcast({ type: 'nowplaying', guildId, name: '' });
|
||||
// Partymode für diese Guild ebenfalls stoppen
|
||||
try {
|
||||
const t = partyTimers.get(guildId);
|
||||
|
|
@ -1240,7 +1252,7 @@ app.get('/api/events', (req: Request, res: Response) => {
|
|||
|
||||
// Snapshot senden
|
||||
try {
|
||||
res.write(`data: ${JSON.stringify({ type: 'snapshot', party: Array.from(partyActive), selected: persistedState.selectedChannels ?? {}, volumes: persistedState.volumes ?? {} })}\n\n`);
|
||||
res.write(`data: ${JSON.stringify({ type: 'snapshot', party: Array.from(partyActive), selected: persistedState.selectedChannels ?? {}, volumes: persistedState.volumes ?? {}, nowplaying: Object.fromEntries(nowPlaying) })}\n\n`);
|
||||
} catch {}
|
||||
|
||||
// Ping, damit Proxies die Verbindung offen halten
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue