14 Commits
Author SHA1 Message Date
chun_qiu 4f7168a0e3 refactor: fake room routing moved to connect-time, fully decoupled from production
- server.py / main.py no longer reference fake_room at all (no import,
  no --fake-room flag, no _apply_fake_room)
- Routing decision happens at connect time in DanmakuClient.start():
  room_id == 1 dynamically imports fake_room.py and patches blivedm;
  any other room id returns immediately without touching fake_room
- Switching back from room 1 to another room unpatches to real Bilibili
- Production (packaged, no fake_room.py) is completely unaffected for
  normal room ids; room 1 without fake_room.py raises a clear error
- Rebuild portable zip (83.9 MB)
2026-08-08 17:59:38 +08:00
chun_qiu d4de39f294 feat: add {gift_count} variable to gift/blind box default rules
- New variable {gift_count} (gift quantity) alongside existing {gift_num}
- Default templates: 感谢由{viewer_name}投喂的{gift_count}个{gift_name}
- danmaku_handler passes gift_count=message.num
- README variable table and examples updated
- Rebuild portable zip (83.9 MB)
2026-08-08 17:41:10 +08:00
chun_qiu d7e940fe2e feat: auto-route room_id 1 to local fake_room.py for testing
- When room_id == 1, server/main automatically patch blivedm to connect
  to fake_room.py on 127.0.0.1:8081 (bot web UI port + 1)
- Any other room id restores real Bilibili (unpatch)
- fake_room.py (gitignored, not packaged): headless fake live room with
  bilibili-compatible init APIs (/x/web-interface/nav, /room/v1/Room/get_info,
  /xlive/web-room/v1/index/getDanmuInfo) and WS /sub protocol (AUTH/HEARTBEAT/
  SEND_MSG_REPLY), plus stdin/HTTP /emit control for danmaku/gift/blind box/
  guard/super chat/enter/follow
- Verified end-to-end: all events flow through blivedm and render rules
  (gift -> 感谢由Baka投喂的小电视, blind box, guard, super chat, custom
  danmaku template, enter room)
2026-08-08 17:25:02 +08:00
chun_qiu 22ee613352 feat: remove like event (unreliable via INTERACT_WORD_V2); restore portable build dir
- Drop 'like' event from rules, handler and web UI (Bilibili like messages
  are not reliably delivered as INTERACT_WORD_V2 msg_type=6)
- Keep enter_room / follow / interact_other
- event_rules.json rewritten without like key
- build.py keeps BUILD_DIR = dist/portable
2026-08-08 17:11:15 +08:00
chun_qiu 6ae7249583 fix: collapse AquesTalk1-unsupported punctuation (!「」・ ) to 、 pause
Probe results: AquesTalk1 rejects U+FF01 !, U+300C/D 「」, U+30FB ・,
U+3000 full-width space with error 105; only 、。?〜ー are safe.
User templates containing ! (e.g. 卧槽!、是{uname}!...) now render
correctly: synthesize() final pass replaces any char outside the safe
kana/punctuation set with a 、 pause.

Verified: custom template full pipeline -> WAV 103316 bytes, no 105.
Rebuild portable zip (80.8 MB)
2026-08-08 16:53:54 +08:00
chun_qiu b7d0c26ad1 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
2026-08-08 16:37:05 +08:00
chun_qiu 488abb9730 i18n: translate web UI to Chinese
- Login/config/rules/status cards fully localized
- Event rule labels, buttons, placeholders and hints in Chinese
- Keep English only in code comments and API internals
2026-08-08 16:20:58 +08:00
chun_qiu f3a71e908e feat: user-customizable event voice rules (gift/blind box/enter/follow/like/guard/super chat)
- New event_rules.py: load/save event_rules.json, robust template renderer
  (missing vars -> empty, empty template -> muted), guard level mapping
- danmaku_handler.py: custom SEND_GIFT callback to extract blind_gift_name;
  implements all event callbacks feeding the TTS queue per user rules
- server.py: GET/POST /api/rules, load rules at startup, pass to client
- Web UI: 'Event Voice Rules' panel (per-event toggle + template + save)
- main.py CLI loads rules; build.py bundles event_rules.json
- skip_free_gift option to mute silver free gifts
- Rebuild portable zip (83.8 MB)
2026-08-08 16:17:28 +08:00
chun_qiu f4c99b1692 fix: serialize TTSBridge IO and TTSService lifecycle to prevent concurrency crashes
- TTSBridge.synthesize wraps stdin/stdout request-response in asyncio.Lock;
  concurrent calls previously caused 'readuntil() called while another
  coroutine is already waiting' and ENOENT (temp dir deleted while bridge
  still reading input.txt)
- TTSService.start/stop guarded by lifecycle lock to prevent race from
  rapid Start clicks creating duplicate bridge/worker/danmaku connections
- Verified: 20 concurrent synthesize calls all succeed with correct WAV
- Rebuild portable zip (83.8 MB)
2026-08-08 15:38:08 +08:00
chun_qiu f27bcfb055 fix: AquesTalk truncates speech on space - use 、 as word separator
Root cause: AquesTalk_Synthe silently drops all text after a space.
English segments previously joined with spaces (word gap), so anything
after the first space was silent. Replace all spaces with 、 (Japanese
comma pause) which AquesTalk supports natively.

- PUNCT_MAP maps space -> 、
- convertEnglishSegment joins words with 、
- synthesize collapses consecutive pauses, strips residual spaces

Verified: 'Actually这个proposal是非常creative的' WAV 19316 -> 79196 bytes
2026-08-08 15:26:55 +08:00
chun_qiu cb22e074af fix: OOV english words now transcribed via phonemize G2P + IPA
- Add phonemize (MIT) rule-based G2P as second fallback tier
- IPA phoneme -> katakana CV-syllable transcription table
- proposal -> プラポーザル, bilibili -> バイリーバイリー (no more letter-spelling)
- Letter spelling kept as last resort only
- Bridge logs SYNTH IN/OUT to stderr; tts.py drains stderr to Python logs
  so conversion results are visible in the server log
- Rebuild portable zip (83.8 MB)
2026-08-08 15:21:00 +08:00
chun_qiu 0c0e63161d feat: replace wanakana with english-to-kana 49K dictionary
- Vendor english-kana-matcher.js (english-to-kana, MIT, 49216 words)
- Rewrite bridge: dictionary lookup + letter-by-letter fallback for OOV words
- Convert English punctuation (,.!?) to Japanese pauses (、。)
- Fix Chinese fullwidth comma being stripped by filter_kana
- Preserve decimal points in numbers (3.5 -> スリーファイブ)
- main.py now applies filter_kana (matches web UI behavior)
- Remove wanakana dependency; rebuild portable zip (82.5 MB)
2026-08-08 15:06:34 +08:00
chun_qiu fd5c732d8a feat: web UI + QR login + portable build
- Add web UI panel (dark theme) at / with REST API
- Add Bilibili QR code scan login with browser header emulation
- Add wanakana for English -> katakana conversion
- Add volume control (0%-200%)
- Add message format with '说、' pause marker
- PyInstaller --onedir build for portable exe
- Rate-limit danmaku logging (1/20)
- Fix aiohttp.access log spam
- Add README.md
2026-08-08 13:22:58 +08:00
chun_qiu 9b277fe2e0 feat: Bilibili Live Danmaku -> Yukkuri TTS Reader
- Python main entry with CLI (--room-id, --voice, --speed)
- blivedm integration for real-time danmaku receiving
- Chinese-to-Japanese katakana conversion (pypinyin + mapping table)
- Node.js persistent bridge for aquestalk.js TTS synthesis
- Audio playback via sounddevice
- Message queue for sequential TTS playback
2026-08-08 11:26:11 +08:00