Count listeners from the room so the bot leaves empty channels
The bot stayed in a channel everyone had left. revoice.js stores voice users by participant identity but removes them by participant name — and Stoat sets those to different things (the user id and username#tag) — so its list never shrinks and the channel never looked empty to us. Participants are now counted from the LiveKit room directly, and the check also runs on a 30s interval, so a participant event that never arrives cannot strand the bot either. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
49b87dc172
commit
1eec893d15
+21
-2
@@ -80,6 +80,7 @@ export class GuildPlayer extends EventEmitter<GuildPlayerEvents> {
|
||||
/** Set while we tear playback down ourselves, so the resulting `finish` is ignored. */
|
||||
private expectingStop = false;
|
||||
private leaveTimer: NodeJS.Timeout | null = null;
|
||||
private presenceTimer: NodeJS.Timeout | null = null;
|
||||
private ticker: NodeJS.Timeout | null = null;
|
||||
private readonly log;
|
||||
|
||||
@@ -214,11 +215,19 @@ export class GuildPlayer extends EventEmitter<GuildPlayerEvents> {
|
||||
|
||||
this.setStatus("idle");
|
||||
this.checkEmptyChannel();
|
||||
// Belt and braces: a participant event we never receive would otherwise
|
||||
// leave the bot sitting in an empty channel indefinitely.
|
||||
this.presenceTimer = setInterval(() => this.checkEmptyChannel(), 30_000);
|
||||
this.presenceTimer.unref?.();
|
||||
this.log.info({ channelId }, "voice connection established");
|
||||
}
|
||||
|
||||
async leaveVoice(): Promise<void> {
|
||||
this.cancelLeaveTimer();
|
||||
if (this.presenceTimer) {
|
||||
clearInterval(this.presenceTimer);
|
||||
this.presenceTimer = null;
|
||||
}
|
||||
this.stopScreenShare();
|
||||
this.stopTicker();
|
||||
this.teardownPlayback();
|
||||
@@ -244,9 +253,19 @@ export class GuildPlayer extends EventEmitter<GuildPlayerEvents> {
|
||||
this.publish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counted straight from the LiveKit room. revoice's own list cannot be
|
||||
* trusted: it stores users by participant identity but removes them by
|
||||
* participant name, so nobody is ever dropped and the channel never looks
|
||||
* empty — the bot would sit in it forever.
|
||||
*/
|
||||
private listenersInChannel(): number {
|
||||
return this.connection?.room?.remoteParticipants?.size ?? 0;
|
||||
}
|
||||
|
||||
private checkEmptyChannel(): void {
|
||||
if (!this.connection) return;
|
||||
if (this.connection.getUsers().length > 0) {
|
||||
if (this.listenersInChannel() > 0) {
|
||||
this.cancelLeaveTimer();
|
||||
return;
|
||||
}
|
||||
@@ -549,7 +568,7 @@ export class GuildPlayer extends EventEmitter<GuildPlayerEvents> {
|
||||
this.cancelLeaveTimer();
|
||||
if (config.EMPTY_TIMEOUT_SECONDS <= 0 || !this.connection) return;
|
||||
this.leaveTimer = setTimeout(() => {
|
||||
if (this.connection && this.connection.getUsers().length > 0) return;
|
||||
if (this.listenersInChannel() > 0) return;
|
||||
this.notify("👋 В канале никого не осталось, выхожу.");
|
||||
void this.leaveVoice();
|
||||
}, config.EMPTY_TIMEOUT_SECONDS * 1000);
|
||||
|
||||
Reference in New Issue
Block a user