mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
fix(player): bigger retry budget + return value for /play-playlist
The previous fix for "播放全部 没有反应" hooked into playNext but had two problems: 1. Used !!queue.current() to detect success, which is always true after queue.next() advanced — so the response message would lie about playback starting even when all retries failed. 2. The default 3-retry budget is sized for "next song couldn't resolve, skip it" cases. User-initiated playlist plays commonly hit long contiguous runs of QQ 104003 songs in collected playlists (entire ACG/古风 packs can be uniformly unstreamable in some regions), so 3-4 attempts wasn't enough. Make playNext return whether a song actually started, and accept a maxRetries parameter. /play-playlist now uses 20 retries — high enough to clear typical unplayable runs, bounded enough that fully unstreamable playlists still surface a clear "none were playable" message rather than hanging. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
82655afa20
commit
4301da2e37
2 files changed
+18
-14
No files matched your search
+13
-9
@@ -736,21 +736,23 @@ export class BotInstance extends EventEmitter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Advance the queue and play the next song. If the resolved URL fails
|
* Advance the queue and play the next song. If the resolved URL fails
|
||||||
* (e.g., copyright/region restrictions for QQ), skips up to 3 more
|
* (e.g., copyright/region restrictions for QQ), skips up to `maxRetries`
|
||||||
* songs looking for a playable one. Public so REST endpoints that
|
* more songs looking for a playable one. Public so REST endpoints that
|
||||||
* seed the queue can fall back to this retry-skip behavior.
|
* seed the queue can fall back to this retry-skip behavior.
|
||||||
|
*
|
||||||
|
* Returns true if a song actually started playing, false otherwise.
|
||||||
*/
|
*/
|
||||||
async playNext(): Promise<void> {
|
async playNext(maxRetries = 3): Promise<boolean> {
|
||||||
if (this.isAdvancing || !this.connected) return;
|
if (this.isAdvancing || !this.connected) return false;
|
||||||
this.isAdvancing = true;
|
this.isAdvancing = true;
|
||||||
try {
|
try {
|
||||||
this.voteSkipUsers.clear();
|
this.voteSkipUsers.clear();
|
||||||
const next = this.queue.next();
|
const next = this.queue.next();
|
||||||
|
let started = false;
|
||||||
if (next) {
|
if (next) {
|
||||||
let started = await this.resolveAndPlay(next);
|
started = await this.resolveAndPlay(next);
|
||||||
if (!started) {
|
if (!started) {
|
||||||
// Skip to next if URL resolve fails (up to 3 retries)
|
for (let i = 0; i < maxRetries && this.connected; i++) {
|
||||||
for (let i = 0; i < 3 && this.connected; i++) {
|
|
||||||
const retry = this.queue.next();
|
const retry = this.queue.next();
|
||||||
if (!retry) break;
|
if (!retry) break;
|
||||||
if (await this.resolveAndPlay(retry)) {
|
if (await this.resolveAndPlay(retry)) {
|
||||||
@@ -772,8 +774,9 @@ export class BotInstance extends EventEmitter {
|
|||||||
await this.refillFm();
|
await this.refillFm();
|
||||||
const refillNext = this.queue.next();
|
const refillNext = this.queue.next();
|
||||||
if (refillNext) {
|
if (refillNext) {
|
||||||
await this.resolveAndPlay(refillNext);
|
started = await this.resolveAndPlay(refillNext);
|
||||||
} else {
|
}
|
||||||
|
if (!started) {
|
||||||
this.player.stop();
|
this.player.stop();
|
||||||
this.profileManager.onSongChange(null).catch(() => {});
|
this.profileManager.onSongChange(null).catch(() => {});
|
||||||
}
|
}
|
||||||
@@ -783,6 +786,7 @@ export class BotInstance extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.emit("stateChange");
|
this.emit("stateChange");
|
||||||
|
return started;
|
||||||
} finally {
|
} finally {
|
||||||
this.isAdvancing = false;
|
this.isAdvancing = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -266,13 +266,13 @@ export function createPlayerRouter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the first picked song can't resolve (e.g., QQ song with no
|
// If the first picked song can't resolve (e.g., QQ song with no
|
||||||
// streaming entitlement → result 104003), fall back to the same
|
// streaming entitlement → result 104003), fall back to playNext's
|
||||||
// retry-skip behavior playNext uses for trackEnd auto-advance.
|
// retry-skip behavior. Use a higher retry budget than the default
|
||||||
// Otherwise the bot would sit silently on a dead song.
|
// trackEnd auto-advance because user-initiated playlist plays
|
||||||
|
// commonly have long contiguous runs of unplayable songs.
|
||||||
let started = first ? await bot.resolveAndPlay(first) : false;
|
let started = first ? await bot.resolveAndPlay(first) : false;
|
||||||
if (first && !started) {
|
if (first && !started) {
|
||||||
await bot.playNext();
|
started = await bot.playNext(20);
|
||||||
started = !!queue.current();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const playing = queue.current();
|
const playing = queue.current();
|
||||||
|
|||||||
Reference in new issue
Block a user