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. */
|
/** Set while we tear playback down ourselves, so the resulting `finish` is ignored. */
|
||||||
private expectingStop = false;
|
private expectingStop = false;
|
||||||
private leaveTimer: NodeJS.Timeout | null = null;
|
private leaveTimer: NodeJS.Timeout | null = null;
|
||||||
|
private presenceTimer: NodeJS.Timeout | null = null;
|
||||||
private ticker: NodeJS.Timeout | null = null;
|
private ticker: NodeJS.Timeout | null = null;
|
||||||
private readonly log;
|
private readonly log;
|
||||||
|
|
||||||
@@ -214,11 +215,19 @@ export class GuildPlayer extends EventEmitter<GuildPlayerEvents> {
|
|||||||
|
|
||||||
this.setStatus("idle");
|
this.setStatus("idle");
|
||||||
this.checkEmptyChannel();
|
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");
|
this.log.info({ channelId }, "voice connection established");
|
||||||
}
|
}
|
||||||
|
|
||||||
async leaveVoice(): Promise<void> {
|
async leaveVoice(): Promise<void> {
|
||||||
this.cancelLeaveTimer();
|
this.cancelLeaveTimer();
|
||||||
|
if (this.presenceTimer) {
|
||||||
|
clearInterval(this.presenceTimer);
|
||||||
|
this.presenceTimer = null;
|
||||||
|
}
|
||||||
this.stopScreenShare();
|
this.stopScreenShare();
|
||||||
this.stopTicker();
|
this.stopTicker();
|
||||||
this.teardownPlayback();
|
this.teardownPlayback();
|
||||||
@@ -244,9 +253,19 @@ export class GuildPlayer extends EventEmitter<GuildPlayerEvents> {
|
|||||||
this.publish();
|
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 {
|
private checkEmptyChannel(): void {
|
||||||
if (!this.connection) return;
|
if (!this.connection) return;
|
||||||
if (this.connection.getUsers().length > 0) {
|
if (this.listenersInChannel() > 0) {
|
||||||
this.cancelLeaveTimer();
|
this.cancelLeaveTimer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -549,7 +568,7 @@ export class GuildPlayer extends EventEmitter<GuildPlayerEvents> {
|
|||||||
this.cancelLeaveTimer();
|
this.cancelLeaveTimer();
|
||||||
if (config.EMPTY_TIMEOUT_SECONDS <= 0 || !this.connection) return;
|
if (config.EMPTY_TIMEOUT_SECONDS <= 0 || !this.connection) return;
|
||||||
this.leaveTimer = setTimeout(() => {
|
this.leaveTimer = setTimeout(() => {
|
||||||
if (this.connection && this.connection.getUsers().length > 0) return;
|
if (this.listenersInChannel() > 0) return;
|
||||||
this.notify("👋 В канале никого не осталось, выхожу.");
|
this.notify("👋 В канале никого не осталось, выхожу.");
|
||||||
void this.leaveVoice();
|
void this.leaveVoice();
|
||||||
}, config.EMPTY_TIMEOUT_SECONDS * 1000);
|
}, config.EMPTY_TIMEOUT_SECONDS * 1000);
|
||||||
|
|||||||
Reference in New Issue
Block a user