From e92628a6b471d9a7d5f0b10dd4051f3b2e97f009 Mon Sep 17 00:00:00 2001 From: saopig1 Date: Mon, 13 Apr 2026 00:48:09 +0800 Subject: [PATCH] fix(profile): add timeout to clientedit, guard clearAvatar with generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Wrap clientedit (description) with 5s timeout to prevent blocking channel description and now-playing updates if the command hangs - Check generation counter in clearAvatar to avoid clearing a newer song's avatar when stop→play happens in quick succession Co-Authored-By: Claude Opus 4.6 (1M context) --- src/bot/profile.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/bot/profile.ts b/src/bot/profile.ts index f8aeb48..8994fa8 100644 --- a/src/bot/profile.ts +++ b/src/bot/profile.ts @@ -114,7 +114,7 @@ export class BotProfileManager { if (!this.config.avatarEnabled || this.permDenied.avatar) return; try { if (!coverUrl) { - await this.clearAvatar(); + await this.clearAvatar(gen); return; } // Request a thumbnail from the CDN to stay within TS3's avatar size limit. @@ -152,7 +152,7 @@ export class BotProfileManager { await this.tsClient.sendCommandNoWait(`clientupdate client_flag_avatar=${escapeTS3(md5)}`); } - private async clearAvatar(): Promise { + private async clearAvatar(gen: number): Promise { try { await this.withTimeout( this.tsClient.fileTransferDeleteFile(0n, ["/avatar"]), @@ -161,6 +161,8 @@ export class BotProfileManager { } catch { // File may not exist or transfer timed out — that's fine } + // Bail if a newer song started while we were deleting + if (this.generation !== gen) return; try { await this.tsClient.sendCommandNoWait("clientupdate client_flag_avatar="); } catch (err) { @@ -183,8 +185,13 @@ export class BotProfileManager { // TS3AudioBot does via TSLib's ChangeDescription(). const clid = this.tsClient.getClientId(); if (clid <= 0) return; - await this.tsClient.execCommand( - `clientedit clid=${clid} client_description=${escapeTS3(text)}`, + // Use a 5s timeout — if clientedit hangs, don't block the + // remaining profile updates (channeledit, now-playing msg). + await this.withTimeout( + this.tsClient.execCommand( + `clientedit clid=${clid} client_description=${escapeTS3(text)}`, + ), + 5000, ); } this.logger.info("Description updated");