feat: live-Volume während Wiedergabe (inlineVolume state) + Anzeige Gesamtanzahl Sounds
This commit is contained in:
parent
826b07e994
commit
9a97a9d7bb
5 changed files with 28 additions and 8 deletions
|
|
@ -12,6 +12,7 @@ import {
|
||||||
NoSubscriberBehavior,
|
NoSubscriberBehavior,
|
||||||
getVoiceConnection,
|
getVoiceConnection,
|
||||||
type VoiceConnection,
|
type VoiceConnection,
|
||||||
|
type AudioResource,
|
||||||
generateDependencyReport,
|
generateDependencyReport,
|
||||||
entersState,
|
entersState,
|
||||||
VoiceConnectionStatus
|
VoiceConnectionStatus
|
||||||
|
|
@ -58,6 +59,8 @@ type GuildAudioState = {
|
||||||
player: ReturnType<typeof createAudioPlayer>;
|
player: ReturnType<typeof createAudioPlayer>;
|
||||||
guildId: string;
|
guildId: string;
|
||||||
channelId: string;
|
channelId: string;
|
||||||
|
currentResource?: AudioResource;
|
||||||
|
currentVolume: number; // 0..1
|
||||||
};
|
};
|
||||||
const guildAudioState = new Map<string, GuildAudioState>();
|
const guildAudioState = new Map<string, GuildAudioState>();
|
||||||
|
|
||||||
|
|
@ -197,7 +200,7 @@ app.get('/api/sounds', (req: Request, res: Response) => {
|
||||||
.map((file) => ({ fileName: file, name: path.parse(file).name }))
|
.map((file) => ({ fileName: file, name: path.parse(file).name }))
|
||||||
.filter((s) => (q ? s.name.toLowerCase().includes(q) : true));
|
.filter((s) => (q ? s.name.toLowerCase().includes(q) : true));
|
||||||
|
|
||||||
res.json(items);
|
res.json({ items, total: files.length });
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/channels', (_req: Request, res: Response) => {
|
app.get('/api/channels', (_req: Request, res: Response) => {
|
||||||
|
|
@ -227,7 +230,7 @@ app.post('/api/play', async (req: Request, res: Response) => {
|
||||||
volume?: number; // 0..1
|
volume?: number; // 0..1
|
||||||
};
|
};
|
||||||
if (!soundName || !guildId || !channelId) return res.status(400).json({ error: 'soundName, guildId, channelId erforderlich' });
|
if (!soundName || !guildId || !channelId) return res.status(400).json({ error: 'soundName, guildId, channelId erforderlich' });
|
||||||
const safeVolume = typeof volume === 'number' && Number.isFinite(volume) ? Math.max(0, Math.min(1, volume)) : 1;
|
const safeVolume = typeof volume === 'number' && Number.isFinite(volume) ? Math.max(0, Math.min(1, volume)) : state?.currentVolume ?? 1;
|
||||||
|
|
||||||
const filePath = path.join(SOUNDS_DIR, `${soundName}.mp3`);
|
const filePath = path.join(SOUNDS_DIR, `${soundName}.mp3`);
|
||||||
if (!fs.existsSync(filePath)) return res.status(404).json({ error: 'Sound nicht gefunden' });
|
if (!fs.existsSync(filePath)) return res.status(404).json({ error: 'Sound nicht gefunden' });
|
||||||
|
|
@ -250,7 +253,7 @@ app.post('/api/play', async (req: Request, res: Response) => {
|
||||||
});
|
});
|
||||||
const player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Play } });
|
const player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Play } });
|
||||||
connection.subscribe(player);
|
connection.subscribe(player);
|
||||||
state = { connection, player, guildId, channelId };
|
state = { connection, player, guildId, channelId, currentVolume: 1 };
|
||||||
guildAudioState.set(guildId, state);
|
guildAudioState.set(guildId, state);
|
||||||
|
|
||||||
// Connection State Logs
|
// Connection State Logs
|
||||||
|
|
@ -297,7 +300,7 @@ app.post('/api/play', async (req: Request, res: Response) => {
|
||||||
});
|
});
|
||||||
const player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Play } });
|
const player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Play } });
|
||||||
connection.subscribe(player);
|
connection.subscribe(player);
|
||||||
state = { connection, player, guildId, channelId };
|
state = { connection, player, guildId, channelId, currentVolume: 1 };
|
||||||
guildAudioState.set(guildId, state);
|
guildAudioState.set(guildId, state);
|
||||||
|
|
||||||
state.connection = await ensureConnectionReady(connection, channelId, guildId, guild);
|
state.connection = await ensureConnectionReady(connection, channelId, guildId, guild);
|
||||||
|
|
@ -323,6 +326,8 @@ app.post('/api/play', async (req: Request, res: Response) => {
|
||||||
}
|
}
|
||||||
state.player.stop();
|
state.player.stop();
|
||||||
state.player.play(resource);
|
state.player.play(resource);
|
||||||
|
state.currentResource = resource;
|
||||||
|
state.currentVolume = safeVolume;
|
||||||
console.log(`${new Date().toISOString()} | player.play() called for ${soundName}`);
|
console.log(`${new Date().toISOString()} | player.play() called for ${soundName}`);
|
||||||
return res.json({ ok: true });
|
return res.json({ ok: true });
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import type { VoiceChannelInfo, Sound } from './types';
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [sounds, setSounds] = useState<Sound[]>([]);
|
const [sounds, setSounds] = useState<Sound[]>([]);
|
||||||
|
const [total, setTotal] = useState<number>(0);
|
||||||
const [channels, setChannels] = useState<VoiceChannelInfo[]>([]);
|
const [channels, setChannels] = useState<VoiceChannelInfo[]>([]);
|
||||||
const [query, setQuery] = useState('');
|
const [query, setQuery] = useState('');
|
||||||
const [selected, setSelected] = useState<string>('');
|
const [selected, setSelected] = useState<string>('');
|
||||||
|
|
@ -15,7 +16,8 @@ export default function App() {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
const [s, c] = await Promise.all([fetchSounds(), fetchChannels()]);
|
const [s, c] = await Promise.all([fetchSounds(), fetchChannels()]);
|
||||||
setSounds(s);
|
setSounds(s.items);
|
||||||
|
setTotal(s.total);
|
||||||
setChannels(c);
|
setChannels(c);
|
||||||
if (c[0]) setSelected(`${c[0].guildId}:${c[0].channelId}`);
|
if (c[0]) setSelected(`${c[0].guildId}:${c[0].channelId}`);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
|
|
@ -26,7 +28,8 @@ export default function App() {
|
||||||
const interval = setInterval(async () => {
|
const interval = setInterval(async () => {
|
||||||
try {
|
try {
|
||||||
const s = await fetchSounds(query);
|
const s = await fetchSounds(query);
|
||||||
setSounds(s);
|
setSounds(s.items);
|
||||||
|
setTotal(s.total);
|
||||||
} catch {}
|
} catch {}
|
||||||
}, 10000);
|
}, 10000);
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
|
|
@ -101,6 +104,7 @@ export default function App() {
|
||||||
))}
|
))}
|
||||||
{filtered.length === 0 && <div className="hint">Keine Sounds gefunden.</div>}
|
{filtered.length === 0 && <div className="hint">Keine Sounds gefunden.</div>}
|
||||||
</section>
|
</section>
|
||||||
|
<div className="footer-info">Geladene Sounds: {total}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import type { Sound, VoiceChannelInfo } from './types';
|
import type { Sound, SoundsResponse, VoiceChannelInfo } from './types';
|
||||||
|
|
||||||
const API_BASE = import.meta.env.VITE_API_BASE_URL || '/api';
|
const API_BASE = import.meta.env.VITE_API_BASE_URL || '/api';
|
||||||
|
|
||||||
export async function fetchSounds(q?: string): Promise<Sound[]> {
|
export async function fetchSounds(q?: string): Promise<SoundsResponse> {
|
||||||
const url = new URL(`${API_BASE}/sounds`, window.location.origin);
|
const url = new URL(`${API_BASE}/sounds`, window.location.origin);
|
||||||
if (q) url.searchParams.set('q', q);
|
if (q) url.searchParams.set('q', q);
|
||||||
const res = await fetch(url.toString());
|
const res = await fetch(url.toString());
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,12 @@ header p { opacity: .8; }
|
||||||
|
|
||||||
.hint { opacity: .7; padding: 24px 0; }
|
.hint { opacity: .7; padding: 24px 0; }
|
||||||
|
|
||||||
|
.footer-info {
|
||||||
|
margin-top: 14px;
|
||||||
|
opacity: .8;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,11 @@ export type Sound = {
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type SoundsResponse = {
|
||||||
|
items: Sound[];
|
||||||
|
total: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type VoiceChannelInfo = {
|
export type VoiceChannelInfo = {
|
||||||
guildId: string;
|
guildId: string;
|
||||||
guildName: string;
|
guildName: string;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue