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
This commit is contained in:
2026-08-08 13:22:58 +08:00
parent 9b277fe2e0
commit fd5c732d8a
13 changed files with 1470 additions and 206 deletions
+7 -14
View File
@@ -4,35 +4,28 @@ import asyncio
import io
import logging
import numpy as np
import sounddevice as sd
import soundfile as sf
logger = logging.getLogger(__name__)
def play_wav(wav_data: bytes) -> None:
"""Play WAV audio data synchronously (blocking).
Args:
wav_data: Raw WAV file bytes.
"""
def play_wav(wav_data: bytes, volume: int = 100) -> None:
data, samplerate = sf.read(io.BytesIO(wav_data), dtype="float32")
if volume != 100:
gain = max(0.0, volume / 100.0)
data = np.clip(data * gain, -1.0, 1.0)
sd.play(data, samplerate)
sd.wait()
async def play_wav_async(wav_data: bytes) -> None:
"""Play WAV audio data asynchronously.
Args:
wav_data: Raw WAV file bytes.
"""
async def play_wav_async(wav_data: bytes, volume: int = 100) -> None:
loop = asyncio.get_running_loop()
await loop.run_in_executor(None, play_wav, wav_data)
await loop.run_in_executor(None, play_wav, wav_data, volume)
def get_output_devices() -> list[dict]:
"""List available audio output devices."""
devices = sd.query_devices()
result = []
for i, dev in enumerate(devices):