mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
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:
1 parent
90019e7424
commit
eb0088d110
4 files changed
+18
-7
No files matched your search
+1
-1
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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" });
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in new issue
Block a user