diff --git a/musicbot/music.py b/musicbot/music.py index 606fe5c..2778e67 100644 --- a/musicbot/music.py +++ b/musicbot/music.py @@ -404,6 +404,7 @@ async def send_menu( logger.warning(f"文本菜单发送失败: {e!r}") return await _swap_message(api, config, group_openid, resp) + logger.info(f"[{group_openid}] 菜单已发:{keyword} 第{page}页 {len(songs)}首") async def send_card( @@ -451,6 +452,7 @@ async def send_card( logger.warning(f"文本卡片发送失败: {e!r}") return await _swap_message(api, config, group_openid, resp) + logger.info(f"[{group_openid}] 选歌:{title}") async def _upload_group_file( @@ -489,6 +491,7 @@ async def send_song( 无论成败都撤回卡片。""" found = await _fetchable_play(http, config, song, keyword) if found is None: + logger.warning(f"[{group_openid}] 无可用直链:{song.name}") await _reply( api, group_openid, f"没拿到「{song.name}」的播放链接", msg_id, event_id ) @@ -510,26 +513,28 @@ async def send_song( ) if sent := _sent_id(resp): _mark(sent) + logger.info(f"[{group_openid}] {label}已发:{_caption(song)}") return except _API_FAILS as e: no_permission = isinstance(e, ApiError) and e.code == _NO_FILE_PERMISSION if no_permission: - logger.warning("群文件上传仅限群主/管理员,改为直链文本") + logger.warning(f"[{group_openid}] 群文件上传无权限,改为直链文本") else: - logger.warning(f"以{label}发送失败: {e!r}") + logger.warning(f"[{group_openid}] 以{label}发送失败: {e!r}") # 回退直链文本;文件权限问题多给一句说明 text = f"{_caption(song)}\n{url}" if no_permission: text = f"{_caption(song)}\n(本群文件上传仅限群主/管理员,先给直链)\n{url}" try: await _reply(api, group_openid, text, msg_id, event_id) + logger.info(f"[{group_openid}] 直链已发:{_caption(song)}") except _API_FAILS as e: # 被动回复被拒(如互动 event_id 超时效)→ 降级为主动消息 - logger.warning(f"被动回复失败,降级为主动消息: {e!r}") + logger.warning(f"[{group_openid}] 被动回复失败,降级为主动消息: {e!r}") try: await _reply(api, group_openid, text) except _API_FAILS as e: - logger.warning(f"文本链接发送失败: {e!r}") + logger.warning(f"[{group_openid}] 文本链接发送失败: {e!r}") async def send_lyric( @@ -688,14 +693,17 @@ async def handle_command( 选歌/播放/下载现在都由内嵌按钮(回调)承担,这里只处理文字命令。""" if match := _SONG_RE.search(content): keyword = match.group(1).strip() + logger.info(f"[{group_openid}] 点歌:{keyword}") await send_menu(api, http, config, group_openid, keyword, msg_id=msg_id) return True if match := _LYRIC_RE.search(content): keyword = match.group(1).strip() + logger.info(f"[{group_openid}] 查歌词:{keyword}") if song := await _find(api, http, config, group_openid, msg_id, keyword): await send_lyric(api, http, config, group_openid, song, msg_id=msg_id) return True if "音乐帮助" in content: + logger.info(f"[{group_openid}] 查看帮助") await _reply(api, group_openid, _HELP, msg_id=msg_id) return True return False @@ -732,6 +740,11 @@ def register(ee: EventEmitter, config: BotConfig, http: ClientSession) -> None: """把点歌命令与按钮回调 handler 挂到 emitter(群场景);http 为 bot 自建连接池(不受 SDK 的 TIMEOUT 约束),经闭包供 handler 使用——不能 用形参注入,否则拿到的是 SDK 那个 5s 超时的连接池。""" + logger.info( + f"点歌已就绪:源={config.music_source or '聚合'} 音质={config.music_quality} " + f"每页={config.menu_page_size} 下载={config.send_mode} " + f"自动撤回={'开' if config.withdraw else '关'}" + ) # @机器人 的消息走前一个事件;开通「接收所有消息」后群内全部消息走 # 全量事件,两个事件字段一致,共用同一个 handler @@ -743,6 +756,7 @@ def register(ee: EventEmitter, config: BotConfig, http: ClientSession) -> None: @ee.on("INTERACTION_CREATE") async def on_button(act: Interaction, ev: Event, api: BotApi) -> None: if act.chat_type == 1 and act.id and act.group_openid: + logger.info(f"[{act.group_openid}] 按钮:{act.button_data[:40]}") # 被动回复的 event_id 用网关帧最外层 id(Event.event_id), # 裸 uuid(act.id)只用于回应互动 await handle_button( diff --git a/musicbot/reload.py b/musicbot/reload.py index 680ab40..91c5abe 100644 --- a/musicbot/reload.py +++ b/musicbot/reload.py @@ -1,7 +1,7 @@ """开发用热重载:监控源码与配置文件,变更后重启 bot 子进程。 进程级重启(而非进程内模块重载):bot 是长连接 + 模块级状态 + handler -闭包,就地重载要清理 pyee 监听器与旧闭包,容易留下幽灵 handler;重启 +闭包,就地重载要清理事件监听器与旧闭包,容易留下幽灵 handler;重启 子进程则状态与闭包都是干净的,代价是重连一次 websocket。 监督进程只负责拉起/杀掉子进程与轮询文件改动,自身不跑 bot;子进程由 diff --git a/uv.lock b/uv.lock index 3ee03db..7673e9a 100644 --- a/uv.lock +++ b/uv.lock @@ -628,18 +628,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, ] -[[package]] -name = "pyee" -version = "14.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1d/f1/fdedc2c75c3e31a330659c85e5793bb18b3397981fbf0844c6dee5b18926/pyee-14.0.0.tar.gz", hash = "sha256:76dd0f4314ecd27f02dc73589dea7fd3853f9b6176d8ef9b122860657e3602de", size = 98760, upload-time = "2026-08-13T04:26:11.021Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/81/12/5347938b1f9a6453f0dbdfcc3e2388a1320ef9b9ec17fbefbc4ab647ea98/pyee-14.0.0-py3-none-any.whl", hash = "sha256:3ac2d3229a9677f7de2c33d7f52fe25b638a46b19c413fea2edc8c6d0a644e4d", size = 15553, upload-time = "2026-08-13T04:26:09.916Z" }, -] - [[package]] name = "pygments" version = "2.21.0" @@ -702,12 +690,11 @@ wheels = [ [[package]] name = "qqbotsdk" version = "0.1.0" -source = { git = "https://gitea.4i.hk/hhhge/qqbotsdk.git#71cbfdaf5d4814d8798304c6e53b5acb6266f1c2" } +source = { git = "https://gitea.4i.hk/hhhge/qqbotsdk.git#b37a53f6e0dec360a3e684fbafd7140ec00a2711" } dependencies = [ { name = "aiohttp" }, { name = "cryptography" }, { name = "loguru" }, - { name = "pyee" }, { name = "python-dotenv" }, { name = "ujson" }, ]