diff --git a/src/web/api/player.ts b/src/web/api/player.ts index 11f164f..1e5c3a2 100644 --- a/src/web/api/player.ts +++ b/src/web/api/player.ts @@ -142,6 +142,32 @@ export function createPlayerRouter( } }); + // Jump to a specific index in the queue (without clearing it) + router.post("/:botId/play-at", async (req, res) => { + try { + const bot = (req as any).bot; + const { index } = req.body; + if (typeof index !== "number" || index < 0) { + res.status(400).json({ error: "index is required" }); + return; + } + const queue = bot.getQueueManager(); + const song = queue.playAt(index); + if (!song) { + res.status(400).json({ error: "Invalid queue index" }); + return; + } + const ok = await bot.resolveAndPlay(song); + if (!ok) { + res.json({ message: `Cannot play: ${song.name}` }); + return; + } + res.json({ message: `Now playing: ${song.name} - ${song.artist}` }); + } catch (err) { + res.status(500).json({ error: (err as Error).message }); + } + }); + router.post("/:botId/playlist", async (req, res) => { try { const bot = (req as any).bot; diff --git a/web/src/components/Queue.vue b/web/src/components/Queue.vue index 9d5a4b2..c7d2fec 100644 --- a/web/src/components/Queue.vue +++ b/web/src/components/Queue.vue @@ -18,6 +18,7 @@ :key="`${song.id}-${i}`" class="queue-item" :class="{ active: store.currentSong?.id === song.id }" + @dblclick="playAtIndex(i)" >
@@ -54,6 +55,11 @@ watch(() => props.open, (isOpen) => { if (isOpen) store.fetchQueue(); }); +async function playAtIndex(index: number) { + await store.playAtIndex(index); + await store.fetchQueue(); +} + async function removeSong(index: number) { if (!store.activeBotId) return; try { @@ -130,6 +136,8 @@ async function removeSong(index: number) { padding: 8px; border-radius: var(--radius-sm); transition: background var(--transition-fast); + cursor: pointer; + user-select: none; &:hover { background: var(--hover-bg); diff --git a/web/src/stores/player.ts b/web/src/stores/player.ts index 46ca251..d9c0e22 100644 --- a/web/src/stores/player.ts +++ b/web/src/stores/player.ts @@ -172,6 +172,13 @@ export const usePlayerStore = defineStore('player', { setTimeout(() => this.syncElapsed(), 500); }, + async playAtIndex(index: number) { + if (!this.activeBotId) return; + await axios.post(`/api/player/${this.activeBotId}/play-at`, { index }); + this.serverElapsed = 0; + this._syncAfterAction(); + }, + async play(query: string, platform = 'netease') { if (!this.activeBotId) return; await axios.post(`/api/player/${this.activeBotId}/play`, { query, platform });