Compare commits

...

7 Commits

Author SHA1 Message Date
7d6373e38b fix(core): properly use on_voice_state_update
This is called for different members updating their own individual voice
states, not just the bot itself. If someone leaves the channel, we get
their view of their voice state.
2026-04-23 11:21:33 -04:00
3a5e182970 fix: rename modules for hot reloading 2026-04-23 11:21:33 -04:00
45b6ccdf22 feat: add direnv 2026-04-13 19:15:52 -04:00
0a80999ca7 refactor(pyproject): set typeCheckingMode to basic 2026-04-11 18:48:33 -04:00
8194268ce1 fix: delete player objects when disconnected 2026-04-11 17:58:29 -04:00
ed3afdbeae fix(channel/leave): delete player 2026-04-11 17:58:29 -04:00
3ca6f487c6 fix(queue/skip): properly deal with player 2026-04-11 17:37:51 -04:00
8 changed files with 59 additions and 42 deletions

6
.envrc Normal file
View File

@@ -0,0 +1,6 @@
dotenv
export VIRTUAL_ENV=."venv"
layout python
use flake

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
.direnv
.env
.venv
__pycache__

View File

@@ -1,4 +1,5 @@
from ... import utils
from ...state import players
from .utils import command_allowed
@@ -19,5 +20,8 @@ async def leave(message):
if not command_allowed(message):
return
if message.guild.id in players:
del players[message.guild.id]
await message.guild.voice_client.disconnect()
await utils.add_check_reaction(message)

View File

@@ -251,7 +251,8 @@ async def skip(message):
if not command_allowed(message):
return
if not players[message.guild.id] and not players[message.guild.id].queue:
if players[message.guild.id] and not players[message.guild.id].queue:
del players[message.guild.id]
message.guild.voice_client.stop()
await utils.reply(
message,

View File

@@ -31,34 +31,34 @@ REACTIONS = {
"pizza": ["🍕"],
}
RELOADABLE_MODULES = [
"arguments",
"audio",
"audio.discord",
"audio.queue",
"audio.utils",
"audio.youtubedl",
"commands",
"commands.bot",
"commands.tools",
"commands.utils",
"commands.voice",
"commands.voice.channel",
"commands.voice.playback",
"commands.voice.playing",
"commands.voice.queue",
"commands.voice.sponsorblock",
"commands.voice.utils",
"constants",
"core",
"events",
"extra",
"fun",
"sponsorblock",
"tasks",
"utils",
"utils.common",
"utils.discord",
"voice",
"errornocord.arguments",
"errornocord.audio",
"errornocord.audio.discord",
"errornocord.audio.queue",
"errornocord.audio.utils",
"errornocord.audio.youtubedl",
"errornocord.commands",
"errornocord.commands.bot",
"errornocord.commands.tools",
"errornocord.commands.utils",
"errornocord.commands.voice",
"errornocord.commands.voice.channel",
"errornocord.commands.voice.playback",
"errornocord.commands.voice.playing",
"errornocord.commands.voice.queue",
"errornocord.commands.voice.sponsorblock",
"errornocord.commands.voice.utils",
"errornocord.constants",
"errornocord.core",
"errornocord.events",
"errornocord.extra",
"errornocord.fun",
"errornocord.sponsorblock",
"errornocord.tasks",
"errornocord.utils",
"errornocord.utils.common",
"errornocord.utils.discord",
"errornocord.voice",
"yt_dlp",
"yt_dlp.version",
]

View File

@@ -15,7 +15,7 @@ import disnake_paginator
from . import commands, utils
from .commands import Command as C
from .constants import EMBED_COLOR, OWNERS, PREFIX, RELOADABLE_MODULES
from .state import client, command_cooldowns, command_locks, idle_tracker
from .state import client, command_cooldowns, command_locks, idle_tracker, players
async def on_message(message, edited=False):
@@ -148,18 +148,20 @@ async def on_message(message, edited=False):
command_locks[(message.guild.id, message.author.id)].release()
async def on_voice_state_update(_, before, after):
def is_empty(channel):
async def on_voice_state_update(member, before, after):
def is_alone(channel):
return [m.id for m in (channel.members if channel else [])] == [client.user.id]
channel = None
if is_empty(before.channel):
channel = before.channel
elif is_empty(after.channel):
channel = after.channel
if member.id == client.user.id and is_alone(after.channel):
if before.channel.guild.id in players:
del players[before.channel.guild.id]
await after.channel.guild.voice_client.disconnect()
return
if channel:
await channel.guild.voice_client.disconnect()
if is_alone(before.channel):
if before.channel.guild.id in players:
del players[before.channel.guild.id]
await before.channel.guild.voice_client.disconnect()
def rreload(reloaded_modules, module):
@@ -183,8 +185,8 @@ def rreload(reloaded_modules, module):
def reload(*_):
reloaded_modules = set()
rreload(reloaded_modules, __import__("core"))
rreload(reloaded_modules, __import__("extra"))
rreload(reloaded_modules, __import__("errornocord.core"))
rreload(reloaded_modules, __import__("errornocord.extra"))
for module in filter(
lambda v: inspect.ismodule(v) and v.__name__ in RELOADABLE_MODULES,
globals().values(),

View File

@@ -4,7 +4,7 @@ import string
import disnake
from youtube_transcript_api._api import YouTubeTranscriptApi
from state import client, kill, players
from .state import client, kill, players
async def transcript(

View File

@@ -8,3 +8,6 @@ errornocord = "errornocord.main:main"
[tool.setuptools.packages.find]
where = ["."]
include = ["errornocord*"]
[tool.basedpyright]
typeCheckingMode = "basic"