fix: edge case bugs + toggle lyrics from player bar and lyrics button

Bugs fixed:
- play-at: stop current playback before jumping to queue index
- playNext retry: use break instead of return to ensure stateChange emits
- sendVoiceData: skip if disconnecting to avoid errors during teardown

UI: player-left and lyrics button now toggle lyrics page (open/close)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
saopig1andClaude Opus 4.6 committed 2026-03-30 14:50:14 +08:00
1 parent 90019e7424
commit eb0088d110
4 files changed
+18 -7

No files matched your search

+1 -1
View File
@@ -491,7 +491,7 @@ export class BotInstance extends EventEmitter {
for (let i = 0; i < 3; i++) { for (let i = 0; i < 3; i++) {
const retry = this.queue.next(); const retry = this.queue.next();
if (!retry) break; if (!retry) break;
if (await this.resolveAndPlay(retry)) return; if (await this.resolveAndPlay(retry)) break;
} }
this.player.stop(); this.player.stop();
} }
+1 -2
View File
@@ -154,8 +154,7 @@ export class TS3Client extends EventEmitter {
} }
sendVoiceData(opusFrame: Buffer): void { sendVoiceData(opusFrame: Buffer): void {
if (!this.client) return; if (!this.client || this.disconnecting) return;
// Codec 5 = CODEC_OPUS_MUSIC
this.client.sendVoice(opusFrame, 5); this.client.sendVoice(opusFrame, 5);
} }
+1
View File
@@ -152,6 +152,7 @@ export function createPlayerRouter(
return; return;
} }
const queue = bot.getQueueManager(); const queue = bot.getQueueManager();
bot.getPlayer().stop(); // Stop current playback first
const song = queue.playAt(index); const song = queue.playAt(index);
if (!song) { if (!song) {
res.status(400).json({ error: "Invalid queue index" }); res.status(400).json({ error: "Invalid queue index" });
+15 -4
View File
@@ -24,13 +24,13 @@
</div> </div>
</div> </div>
<RouterLink to="/lyrics" class="player-left"> <div class="player-left" @click="toggleLyrics">
<CoverArt :url="currentSong.coverUrl" :size="40" /> <CoverArt :url="currentSong.coverUrl" :size="40" />
<div class="song-info"> <div class="song-info">
<div class="song-name">{{ currentSong.name }}</div> <div class="song-name">{{ currentSong.name }}</div>
<div class="song-artist">{{ currentSong.artist }}</div> <div class="song-artist">{{ currentSong.artist }}</div>
</div> </div>
</RouterLink> </div>
<div class="player-center"> <div class="player-center">
<span class="time-display time-current">{{ formatTime(currentElapsed) }}</span> <span class="time-display time-current">{{ formatTime(currentElapsed) }}</span>
@@ -63,9 +63,9 @@
<button class="control-btn" :class="{ active: showQueue }" @click="showQueue = !showQueue"> <button class="control-btn" :class="{ active: showQueue }" @click="showQueue = !showQueue">
<Icon icon="mdi:playlist-music" /> <Icon icon="mdi:playlist-music" />
</button> </button>
<RouterLink to="/lyrics" class="control-btn lyrics-btn"> <button class="control-btn lyrics-btn" :class="{ active: route.path === '/lyrics' }" @click="toggleLyrics">
<Icon icon="mdi:microphone" /> <Icon icon="mdi:microphone" />
</RouterLink> </button>
</div> </div>
</div> </div>
</div> </div>
@@ -74,16 +74,27 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, onMounted, onUnmounted } from 'vue'; import { computed, ref, onMounted, onUnmounted } from 'vue';
import { Icon } from '@iconify/vue'; import { Icon } from '@iconify/vue';
import { useRoute, useRouter } from 'vue-router';
import { usePlayerStore } from '../stores/player.js'; import { usePlayerStore } from '../stores/player.js';
import CoverArt from './CoverArt.vue'; import CoverArt from './CoverArt.vue';
import Queue from './Queue.vue'; import Queue from './Queue.vue';
const route = useRoute();
const router = useRouter();
const showQueue = ref(false); const showQueue = ref(false);
const store = usePlayerStore(); const store = usePlayerStore();
const activeBot = computed(() => store.activeBot); const activeBot = computed(() => store.activeBot);
const currentSong = computed(() => store.currentSong); const currentSong = computed(() => store.currentSong);
function toggleLyrics() {
if (route.path === '/lyrics') {
router.back();
} else {
router.push('/lyrics');
}
}
// Progress — use manual timer instead of relying on reactive getters // Progress — use manual timer instead of relying on reactive getters
const currentElapsed = ref(0); const currentElapsed = ref(0);
const progressPercent = ref(0); const progressPercent = ref(0);