Skip to content

Buttons on Now Playing and slash commands - #45

Merged
Isma-L154 merged 4 commits into
mainfrom
feature/interactive-controls
Sep 27, 2026
Merged

Isma-L154 merged 4 commits into
mainfrom
feature/interactive-controls

Conversation

@Isma-L154

Copy link
Copy Markdown
Owner

Closes #44

What changes for users

  • Buttons on every Now Playing message: ⏮ ⏯ ⏭ ⏹ / 🔁 🔀 📜 🎤. Anyone in the bot's voice channel can use them; anyone else gets a private refusal. Pause and loop update the message in place; skip, previous, stop and shuffle post a line naming who pressed them; the queue is shown privately; the microphone posts live lyrics. When the next song starts, the previous message's buttons are greyed out.
  • Every command also works as /command. /play suggests searches as you type, /loop and /effect offer their options, /volume enforces 0–100. Errors under / are visible only to whoever caused them. Aliases (!p, !bass…) stay !-only.
  • !effect <name> / /effect name: applies an effect; !effect alone still shows the active one.

How it is built

  • utils/controls.py: playback actions returning an Outcome, shared by commands and buttons so both say the same thing.
  • utils/now_playing_view.py: the buttons. The lyrics button reaches the Lyrics cog through a provider the cog registers on load, so the view never imports a cog.
  • utils/announcer.py: retires the previous controls. Retired views are stopped; a timeout=None view that is never stopped stays in discord.py's view store for the life of the process.
  • /play defers first (voice + yt-dlp outlast Discord's 3s), and replies "Starting …" when Now Playing takes over, so the interaction is never left "thinking".
  • /lyrics posts the live message to the channel, not as the interaction reply: an interaction reply can only be edited for 15 minutes, and the live message is edited for as long as the music plays.
  • utils/errors.py unwraps HybridCommandError → app_commands.CommandInvokeError, and reports RangeError with its bounds.
  • Slash commands are declared guild-only, and are registered by an owner-only, hidden !sync (cogs/admin.py) instead of at every start, because Discord rate-limits syncing and the bot restarts unattended.
  • utils/context.hybrid_command: commands.hybrid_command under a signature mypy can check on cog methods (it cannot solve discord.py's own union of Concatenate types there).

Design: docs/design/2026-09-27-interactive-controls.md.

Testing

ruff, mypy and pytest: 577 passed, 1 skipped (POSIX-only), up from 506. New tests cover the controls, every button (including refusals and a destroyed player), retiring, the suggestion endpoint's failure modes, slash-specific replies and error unwrapping. The slash command payload was built and serialised locally: 20 commands, all guild-only, with the expected choices, range and autocomplete.

After deploying, send !sync once from the bot owner's account, then check in a server:

  1. /play with a search: suggestions appear, "Starting …" answers, Now Playing shows both button rows.
  2. Each button from inside the voice channel; any button from outside it (private refusal).
  3. Skip: the old message's buttons turn grey and the new one's work.
  4. ⏹, then press a button on that message: it is disabled.
  5. /lyrics and the 🎤 button on a song with synced lyrics.
  6. /effect with no option, then with nightcore; /volume 150 is rejected by Discord itself.

Pause, skip, previous, stop, loop, shuffle, queue and lyrics can be used
from buttons by anyone in the bot's voice channel. The actions live in
utils/controls.py so commands and buttons share one implementation and
one wording. When the next track starts, or the player is destroyed, the
previous message's buttons are disabled and its view is stopped, so views
never pile up in discord.py's store.
Commands are hybrid: each answers to both !name and /name. /play defers
before joining voice, answers even when Now Playing takes over, and
suggests searches as you type. /loop and /effect offer their choices, and
/volume its range. Errors and refusals are ephemeral under /, and the
error handler unwraps the extra layer slash commands add. Slash commands
are registered by an owner-only !sync rather than at every start.
@Isma-L154
Isma-L154 merged commit b5aaabe into main Sep 27, 2026
3 checks passed
@Isma-L154
Isma-L154 deleted the feature/interactive-controls branch September 27, 2026 09:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Buttons on Now Playing and slash commands

1 participant