Tidy chat output and pick search results by reaction
A search reply carried ten markdown links, and Stoat expands every link into a full-size player — the result was a wall of embeds burying the list. Stoat's embed generator skips links inside code spans or angle brackets, so links now go out quietly, and list lines carry no links at all: title, artist, length, source. Only `!nowplaying` keeps a preview, where it was asked for. Choosing a track no longer needs a second command: the results message gets 1️⃣–5️⃣ reactions and picking one queues the track, with `!pick` still there when reactions fail or five results are not enough. Only the person who searched can pick, so a list cannot be hijacked. Also `!playvideo` to turn video on and queue a track in one go, and setVideo no longer requires a running player — the switch is a setting, and demanding a player made it fail on a server nothing had played on. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
7cca374e66
commit
e7e80e704b
+34
-4
@@ -3,7 +3,7 @@ import { config } from "../config.js";
|
||||
import { logger } from "../logger.js";
|
||||
import type { MusicManager } from "../core/manager.js";
|
||||
import { UserFacingError } from "../types.js";
|
||||
import { findCommand, type CommandContext } from "./commands.js";
|
||||
import { enqueueChoice, findCommand, trackForReaction, type CommandContext } from "./commands.js";
|
||||
import { BotStoatContext } from "./context.js";
|
||||
|
||||
const log = logger.child({ mod: "bot" });
|
||||
@@ -33,6 +33,13 @@ export async function startBot(manager: MusicManager): Promise<Bot> {
|
||||
});
|
||||
});
|
||||
|
||||
client.on("messageReactionAdd", (message, userId, emoji) => {
|
||||
if (userId === client.user?.id) return;
|
||||
void handleChoice(manager, message, userId, emoji).catch((err) => {
|
||||
log.error({ err }, "unhandled reaction failure");
|
||||
});
|
||||
});
|
||||
|
||||
await client.loginBot(config.STOAT_BOT_TOKEN);
|
||||
|
||||
return {
|
||||
@@ -44,15 +51,38 @@ export async function startBot(manager: MusicManager): Promise<Bot> {
|
||||
};
|
||||
}
|
||||
|
||||
/** Picking a search result by reacting to the bot's list of choices. */
|
||||
async function handleChoice(
|
||||
manager: MusicManager,
|
||||
message: Message,
|
||||
userId: string,
|
||||
emoji: string,
|
||||
): Promise<void> {
|
||||
const serverId = message.server?.id;
|
||||
if (!serverId) return;
|
||||
const track = trackForReaction(message.id, userId, emoji);
|
||||
if (!track) return;
|
||||
|
||||
const username = message.server?.getMember(userId)?.nickname ?? track.requestedBy.username;
|
||||
try {
|
||||
const text = await enqueueChoice(manager, serverId, message.channelId, { id: userId, username }, track);
|
||||
await message.channel?.sendMessage(text);
|
||||
} catch (err) {
|
||||
if (err instanceof UserFacingError) {
|
||||
await message.channel?.sendMessage(`⚠️ ${err.message}`);
|
||||
return;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleMessage(manager: MusicManager, message: Message): Promise<void> {
|
||||
const content = message.content?.trim();
|
||||
if (!content || !content.startsWith(config.COMMAND_PREFIX)) return;
|
||||
if (!message.authorId || message.author?.bot) return;
|
||||
|
||||
const serverId = message.server?.id;
|
||||
const reply = async (text: string) => {
|
||||
await message.channel?.sendMessage(text);
|
||||
};
|
||||
const reply = async (text: string) => message.channel?.sendMessage(text);
|
||||
|
||||
if (!serverId) {
|
||||
await reply("Команды работают только внутри сервера.");
|
||||
|
||||
Reference in New Issue
Block a user