How HoshinoBot Handles Group Events: Join and Leave Notifications Explained
HoshinoBot processes group join and leave events through OneBot notice events, using the Service.on_notice decorator in hoshino/service.py to register handlers that check service permissions before executing welcome or farewell messages.
HoshinoBot, an open-source QQ bot framework built on NoneBot, provides a structured approach to handling group member changes. When users join or leave a group, the bot intercepts these group events through OneBot protocol notices and executes configurable responses. This article examines the exact code paths, configuration methods, and extension points for these notifications.
Core Architecture: The Service.on_notice Decorator
All group event handlers in HoshinoBot rely on the Service.on_notice decorator defined in hoshino/service.py. This method wraps NoneBot's native event dispatcher with service-level permission checks.
# hoshino/service.py
def on_notice(self, *events):
def deco(func):
@wraps(func)
async def wrapper(session):
# ① Service enabled for the group?
if not self.check_enabled(session.event.group_id):
return
# ② Call the user‑defined coroutine
return await func(session)
# ③ Register with nonebot’s notice dispatcher
return nonebot.on_notice(*events)(wrapper)
return deco
The wrapper performs three critical functions: it verifies the service is enabled for the specific group using self.check_enabled, executes the handler coroutine if permitted, and registers the wrapped function with NoneBot's underlying on_notice dispatcher. Event strings such as 'group_increase' or 'group_decrease.leave' map directly to OneBot notice payloads.
Handling Group Join Events (Member Welcome)
New member announcements are handled by the built-in group-welcome service in hoshino/modules/groupmaster/group_notice.py.
The group_increase Event Handler
# hoshino/modules/groupmaster/group_notice.py
sv2 = Service('group-welcome', help_='入群欢迎')
@sv2.on_notice('group_increase')
async def increace_welcome(session: NoticeSession):
if session.event.user_id == session.event.self_id:
return # ignore the bot itself
welcomes = hoshino.config.groupmaster.increase_welcome
gid = session.event.group_id
if gid in welcomes:
await session.send(welcomes[gid], at_sender=True)
When OneBot emits a group_increase notice, the handler first filters out events triggered by the bot itself. It then retrieves the welcome message dictionary from hoshino.config.groupmaster.increase_welcome and checks for a group-specific entry. If found, it sends the message while mentioning the new member via at_sender=True.
Configuration Options
Welcome messages are configured in hoshino/config_example/groupmaster.py:
# hoshino/config_example/groupmaster.py
increase_welcome = {
"default": "欢迎入群!",
1000000: "欢迎新群员",
}
The configuration supports a "default" key for global fallback messages and integer keys representing specific group IDs for customized greetings.
Handling Group Leave Events (Member Departure)
Member departure notifications use the group-leave-notice service, defined in the same file as the welcome handler.
The group_decrease.leave Event Handler
# hoshino/modules/groupmaster/group_notice.py
sv1 = Service('group-leave-notice', help_='退群通知')
@sv1.on_notice('group_decrease.leave')
async def leave_notice(session: NoticeSession):
ev = session.event
if ev.user_id == ev.self_id:
return # ignore the bot itself
try:
info = await session.bot.get_stranger_info(self_id=ev.self_id,
user_id=ev.user_id)
name = info['nickname'] or ev.user_id
name = util.filt_message(name)
except CQHttpError as e:
sv1.logger.exception(e)
name = ev.user_id
await session.send(f"{name}({ev.user_id})退群了。")
This handler listens for group_decrease.leave notices. It attempts to resolve the departing user's nickname via the get_stranger_info API, filters the name for safety using util.filt_message, and broadcasts a formatted departure message. Error handling ensures the notification still fires even if the API call fails.
Auto-Approving Join Requests
Join requests differ from notices—they are request events. The join_approve module in hoshino/modules/groupmaster/join_approve.py handles these using nonebot.on_request directly rather than Service.on_notice.
# hoshino/modules/groupmaster/join_approve.py
@on_request('group.add')
async def join_approve(session: RequestSession):
cfg = hoshino.config.groupmaster.join_approve
gid = session.event.group_id
if gid not in cfg:
return
for k in cfg[gid].get('keywords', []):
if k in session.event.comment:
await session.approve()
return
if cfg[gid].get('reject_when_not_match', False):
await session.reject()
This handler checks join request comments against configured keywords. If a match exists, it auto-approves the request; otherwise, it can optionally reject the request based on the reject_when_not_match setting.
Customizing Group Event Handlers
Developers can extend HoshinoBot's group event handling by creating custom services. Below is a complete example demonstrating custom welcome and leave logic:
# my_custom_group_events.py
from hoshino import Service, util
# 1️⃣ Define a new service (optional – can reuse the built‑in one)
sv = Service('my-group-events', help_='自定义入群/退群通知')
# 2️⃣ Welcome new members with a random quote
@sv.on_notice('group_increase')
async def welcome(session):
quotes = ["欢迎加入!", "欢迎新人~", "大家好,新朋友!"]
await session.send(util.random.choice(quotes), at_sender=True)
# 3️⃣ Leave notice that includes the time the user spent (requires extra DB logic)
@sv.on_notice('group_decrease.leave')
async def goodbye(session):
uid = session.event.user_id
# pretend we fetched join_time from a DB
join_time = await get_user_join_timestamp(session.event.group_id, uid)
duration = datetime.utcnow() - join_time
msg = f"用户 {uid} 已离开本群,已在本群 {duration.days} 天。"
await session.send(msg)
Register this module in your bot's initialization sequence to activate the custom handlers. The Service wrapper automatically handles enable/disable commands and group-specific permissions.
Summary
- HoshinoBot group events are handled via OneBot notice events (
group_increase,group_decrease.leave) and request events (group.add). - The
Service.on_noticedecorator inhoshino/service.pyprovides a unified registration mechanism with built-in permission checks. - Welcome messages are configured via
increase_welcomeinhoshino/config_example/groupmaster.pyand processed inhoshino/modules/groupmaster/group_notice.py. - Leave notifications fetch user nicknames via
get_stranger_infoand broadcast formatted messages through the same module. - Auto-approval of join requests uses
nonebot.on_requestdirectly inhoshino/modules/groupmaster/join_approve.pyto match keywords against request comments.
Frequently Asked Questions
What is the difference between group_increase and group.add events in HoshinoBot?
The group_increase event is a notice event triggered after a member has already joined the group, used for welcome messages. The group.add event is a request event triggered when someone applies to join but requires admin approval, used for auto-approval logic in join_approve.py.
How do I disable group welcome messages for specific groups?
Use the bot's command interface to disable the group-welcome service for specific groups. Since Service.on_notice checks self.check_enabled(session.event.group_id) before executing handlers, disabling the service via the management commands will prevent welcome messages in those groups without modifying code.
Can HoshinoBot fetch user nicknames when someone leaves the group?
Yes. The built-in group-leave-notice handler in hoshino/modules/groupmaster/group_notice.py calls session.bot.get_stranger_info(self_id=ev.self_id, user_id=ev.user_id) to retrieve the user's nickname. If the API call fails, it falls back to displaying the raw user ID.
Where are the group event configurations stored in HoshinoBot?
Configuration templates are located in hoshino/config_example/groupmaster.py, which defines increase_welcome for welcome messages and join_approve for auto-approval keywords. You should copy this file to your actual configuration directory and modify the dictionaries to map group IDs to specific messages or approval rules.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →