fix: danmaku template now uses event rules; rules apply instantly on save

- _on_danmaku renders via event_text(rules, 'danmaku', ...) like all other
  events; hardcoded {uname}说、 {msg} format removed
- Drop message_format param from DanmakuHandler/DanmakuClient/server/main
- api_rules_post mutates the shared rules dict in place (clear+update)
  instead of rebinding, so running handlers pick up new templates
  immediately without restarting TTS
- UI save toast: '规则已保存并即时生效'
- Verified: custom template 卧槽!、是{uname}!、他说、 {msg} works;
  save-then-next-danmaku uses new template without restart
This commit is contained in:
2026-08-08 16:37:05 +08:00
parent 488abb9730
commit b7d0c26ad1
4 changed files with 14 additions and 22 deletions
+8 -13
View File
@@ -20,8 +20,6 @@ from event_rules import (
logger = logging.getLogger(__name__)
DANMAKU_FORMAT = "{uname}\u8bf4\u3001 {msg}"
INTERACT_TYPE_NAMES = {
3: "\u5206\u4eab", 4: "\u7279\u522b\u5173\u6ce8", 5: "\u4e92\u7c89",
}
@@ -32,12 +30,10 @@ class DanmakuHandler(blivedm.BaseHandler):
_CMD_CALLBACK_DICT = blivedm.BaseHandler._CMD_CALLBACK_DICT.copy()
def __init__(self, queue: asyncio.Queue, rules: dict | None = None,
message_format: str = DANMAKU_FORMAT):
def __init__(self, queue: asyncio.Queue, rules: dict | None = None):
super().__init__()
self._queue = queue
self._rules = rules or dict(DEFAULT_RULES)
self._message_format = message_format
self._count = 0
# ── custom SEND_GIFT callback to capture blind-gift info ──────────
@@ -62,11 +58,12 @@ class DanmakuHandler(blivedm.BaseHandler):
def _on_danmaku(self, client: blivedm.BLiveClient, message: DanmakuMessage) -> None:
if not message.msg.strip():
return
text = self._message_format.format(
uname=message.uname,
msg=message.msg,
uid=message.uid,
)
text = event_text(self._rules, "danmaku",
uname=message.uname,
msg=message.msg,
uid=message.uid)
if not text:
return
self._count += 1
if self._count % 20 == 1:
logger.info("Danmaku #%d: %s", self._count, text)
@@ -173,13 +170,11 @@ class DanmakuClient:
queue: asyncio.Queue,
cookies: Optional[dict[str, str]] = None,
rules: dict | None = None,
message_format: str = DANMAKU_FORMAT,
):
self._room_id = room_id
self._queue = queue
self._cookies = cookies
self._rules = rules or dict(DEFAULT_RULES)
self._message_format = message_format
self._client: Optional[blivedm.BLiveClient] = None
self._session: Optional["aiohttp.ClientSession"] = None
@@ -187,7 +182,7 @@ class DanmakuClient:
import aiohttp
self._session = await build_danmaku_session(self._cookies)
self._client = blivedm.BLiveClient(self._room_id, session=self._session)
handler = DanmakuHandler(self._queue, self._rules, self._message_format)
handler = DanmakuHandler(self._queue, self._rules)
self._client.set_handler(handler)
self._client.start()
logger.info("Connected to room %d", self._room_id)
-3
View File
@@ -30,8 +30,6 @@ def parse_args() -> argparse.Namespace:
choices=["f1", "f2", "m1", "m2", "dvd", "imd1", "jgr", "r1"])
parser.add_argument("--speed", "-s", type=int, default=DEFAULT_SPEED)
parser.add_argument("--sessdata", type=str, default="")
parser.add_argument("--format", "-f", type=str,
default="{uname}\u8bf4\u3001 {msg}")
parser.add_argument("--no-numbers", action="store_true")
parser.add_argument("--list-devices", action="store_true")
parser.add_argument("--debug", "-d", action="store_true")
@@ -77,7 +75,6 @@ async def main_async(args: argparse.Namespace) -> int:
room_id=args.room_id, queue=queue,
cookies={"SESSDATA": args.sessdata} if args.sessdata else None,
rules=rules,
message_format=args.format,
)
async def handle_signal():
+5 -5
View File
@@ -58,7 +58,6 @@ class TTSService:
voice = config.get("voice", "f1")
speed = config.get("speed", 100)
self._volume = config.get("volume", 100)
message_format = config.get("format", "{uname}\u8bf4\u3001 {msg}")
convert_numbers = config.get("convert_numbers", True)
self.current_config = config
self.recent_messages = []
@@ -71,7 +70,6 @@ class TTSService:
self._danmaku_client = DanmakuClient(
room_id=room_id, queue=self._queue,
cookies=self._cookies, rules=event_rules,
message_format=message_format,
)
await self._danmaku_client.start()
self.running = True
@@ -169,7 +167,6 @@ async def api_start(request: web.Request) -> web.Response:
config.setdefault("voice", "f1")
config.setdefault("speed", 100)
config.setdefault("volume", 100)
config.setdefault("format", "{uname}\u8bf4\u3001 {msg}")
config.setdefault("convert_numbers", True)
if tts_service.running:
try:
@@ -248,7 +245,6 @@ async def api_rules_get(request: web.Request) -> web.Response:
async def api_rules_post(request: web.Request) -> web.Response:
global event_rules
try:
new_rules = await request.json()
except Exception:
@@ -275,7 +271,11 @@ async def api_rules_post(request: web.Request) -> web.Response:
save_rules(merged)
except OSError as e:
return web.json_response({"error": f"Failed to save rules: {e}"}, status=500)
event_rules = merged
# Mutate in place so running handlers (which hold the same dict reference)
# pick up the new rules immediately without restarting TTS.
event_rules.clear()
event_rules.update(merged)
return web.json_response({"status": "saved", "rules": event_rules})
+1 -1
View File
@@ -634,7 +634,7 @@ async function saveRules() {
const data = await resp.json();
if (data.error) { alert('保存失败: ' + data.error); return; }
renderRules(data.rules);
alert('规则已保存。重启TTS后生效。');
alert('规则已保存并即时生效。');
} catch(e) {
alert('保存失败: ' + e.message);
}