Buttons on Now Playing and slash commands - #45
Merged
Merged
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #44
What changes for users
⏮ ⏯ ⏭ ⏹/🔁 🔀 📜 🎤. 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./command./playsuggests searches as you type,/loopand/effectoffer their options,/volumeenforces 0–100. Errors under/are visible only to whoever caused them. Aliases (!p,!bass…) stay!-only.!effect <name>//effect name:applies an effect;!effectalone still shows the active one.How it is built
utils/controls.py: playback actions returning anOutcome, 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; atimeout=Noneview that is never stopped stays in discord.py's view store for the life of the process./playdefers first (voice + yt-dlp outlast Discord's 3s), and replies "Starting …" when Now Playing takes over, so the interaction is never left "thinking"./lyricsposts 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.pyunwrapsHybridCommandError→app_commands.CommandInvokeError, and reportsRangeErrorwith its bounds.!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_commandunder a signature mypy can check on cog methods (it cannot solve discord.py's own union ofConcatenatetypes there).Design:
docs/design/2026-09-27-interactive-controls.md.Testing
ruff,mypyandpytest: 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
!synconce from the bot owner's account, then check in a server:/playwith a search: suggestions appear, "Starting …" answers, Now Playing shows both button rows.⏹, then press a button on that message: it is disabled./lyricsand the🎤button on a song with synced lyrics./effectwith no option, then withnightcore;/volume 150is rejected by Discord itself.