refactor: restructure plugins per MTSS standard, consolidate assets to res/
Per docs/plugin-audit-report.md (plugins normalized to Trigger(handlers) → Service(services) → Model(repository/models) + utils): - Split monolithic __init__.py into handlers/services/utils across dailywife, deer_pipe, dice, galgame_card, helldivers_tools, huoziyinshua, learning_chat, makeaquote, mc_server_status, ncm_saying, picfinder_take, picstatus, random_jm_code, regif, steam_info, video_analysis, group_tools - Move static assets under res/: deer_pipe font/img, makeaquote font, helldivers img/templates, huoziyinshua HuoZiYinShua - Add config.py + register_config_items to ncm_saying, random_jm_code, group_tools; learning_chat unified config bridge - Remove deprecated: voice_trans plugin, bf_bot/test.py, dead code in dailywife/deer_pipe, empty dirs, debug scripts under helldivers temp - Disable brash_general_supercredits_tools (stub comment only) - bot.py: optional stdout/stderr redirect to log file for Web log viewer, force ANSI colorize on non-TTY sinks - Move runtime data (jm_code.json) out of plugin dir into hexi/data - Docs: plugin-audit-report.md; README reflects removed plugins Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
"""otto 活字印刷 —— Trigger 层。"""
|
||||
|
||||
from .otto import otto # noqa: F401
|
||||
@@ -0,0 +1,83 @@
|
||||
"""otto 活字印刷 —— 触发器(Trigger)层。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import base64
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from nonebot import get_driver, on_startswith, require
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent
|
||||
from nonebot.plugin import PluginMetadata
|
||||
from nonebot_plugin_alconna import UniMessage
|
||||
|
||||
from .. import _TEMP_ROOT
|
||||
from ..services.synthesis import synthesize
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
|
||||
__plugin_meta__ = PluginMetadata(
|
||||
name="otto活字印刷",
|
||||
description="鬼畜音源活字印刷(otto语音合成)",
|
||||
usage="otto 一些内容 生成otto语音\notto 一些内容 -reverse 生成并倒放",
|
||||
type="application",
|
||||
)
|
||||
|
||||
otto = on_startswith("otto")
|
||||
|
||||
|
||||
async def _remove_later(path: Path) -> None:
|
||||
"""发送完成后延迟清理临时音频,避免 NapCat 还在下载/转码时被删。"""
|
||||
await asyncio.sleep(300)
|
||||
path.unlink(missing_ok=True)
|
||||
|
||||
|
||||
def _public_base() -> str:
|
||||
"""构造对外可达的 bot HTTP 地址,供协议端跨机器下载音频。
|
||||
|
||||
优先读 .env 的 OTTO_PUBLIC_BASE_URL(例如 http://192.168.2.100:39697
|
||||
或公网地址);未配置时回退为 HOST:PORT,且 0.0.0.0 自动替换成本机可路由 IP。
|
||||
"""
|
||||
base = os.getenv("OTTO_PUBLIC_BASE_URL", "").strip().rstrip("/")
|
||||
if base:
|
||||
return base
|
||||
cfg = get_driver().config
|
||||
host = str(getattr(cfg, "host", None) or os.getenv("HOST", "0.0.0.0"))
|
||||
port = str(getattr(cfg, "port", None) or os.getenv("PORT", "39697"))
|
||||
if host in ("0.0.0.0", "::", ""):
|
||||
try:
|
||||
# 用 UDP connect 探测本机对外(路由) IP,不真正发包
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.connect(("8.8.8.8", 80))
|
||||
host = s.getsockname()[0]
|
||||
s.close()
|
||||
except OSError:
|
||||
host = "127.0.0.1"
|
||||
return f"http://{host}:{port}"
|
||||
|
||||
|
||||
@otto.handle()
|
||||
async def otto_handle(ev: MessageEvent):
|
||||
txt = ev.message.extract_plain_text().removeprefix("otto")
|
||||
pattern_reverse = re.compile(r"-reverse\s*$")
|
||||
if re.search(pattern_reverse, txt):
|
||||
reverse = True
|
||||
txt = re.sub(pattern_reverse, "", txt)
|
||||
txt = ",,," + txt
|
||||
else:
|
||||
reverse = False
|
||||
txt = txt + ",,,"
|
||||
b64audio = await synthesize(txt, reverse)
|
||||
audio_bytes = base64.b64decode(b64audio)
|
||||
_TEMP_ROOT.mkdir(parents=True, exist_ok=True)
|
||||
mp3_path = _TEMP_ROOT / f"otto-{time.time_ns()}.mp3"
|
||||
mp3_path.write_bytes(audio_bytes)
|
||||
url = f"{_public_base()}/api/otto/{mp3_path.name}"
|
||||
try:
|
||||
await UniMessage.voice(url=url).send()
|
||||
finally:
|
||||
asyncio.create_task(_remove_later(mp3_path))
|
||||
Reference in New Issue
Block a user