Files
MoviePilot/app/modules/vocechat/__init__.py
Aqr-K 825fc35134 feat(modules): 增加子级 type 分类。
- 在 `types` 里,针对各个模块的类型进行子级分类。
- 为每个模块统一添加 `get_subtype` 方法,这样一来,能更精准快速地区分与调用子类的每个模块,又能获取 ModuleType 所规定的分类以及对应存在的子模块类型支持列表,从而有效解决当下调用时需繁琐遍历每个 module 以获取 get_name 或 _channel 的问题。
- 解决因消息渠道前端返回所保存的 type 与后端规定值不一致,而需要频繁调用 _channel 私有方法才能获取分类所可能产生的问题。
2024-12-03 14:57:19 +08:00

185 lines
6.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import json
from typing import Optional, Union, List, Tuple, Any, Dict
from app.core.context import Context, MediaInfo
from app.log import logger
from app.modules import _ModuleBase, _MessageBase
from app.modules.vocechat.vocechat import VoceChat
from app.schemas import MessageChannel, CommingMessage, Notification
from app.schemas.types import ModuleType
class VoceChatModule(_ModuleBase, _MessageBase[VoceChat]):
def init_module(self) -> None:
"""
初始化模块
"""
super().init_service(service_name=VoceChat.__name__.lower(),
service_type=VoceChat)
self._channel = MessageChannel.VoceChat
@staticmethod
def get_name() -> str:
return "VoceChat"
@staticmethod
def get_type() -> ModuleType:
"""
获取模块类型
"""
return ModuleType.Notification
@staticmethod
def get_subtype() -> MessageChannel:
"""
获取模块子类型
"""
return MessageChannel.VoceChat
@staticmethod
def get_priority() -> int:
"""
获取模块优先级,数字越小优先级越高,只有同一接口下优先级才生效
"""
return 4
def stop(self):
pass
def test(self) -> Optional[Tuple[bool, str]]:
"""
测试模块连接性
"""
if not self.get_instances():
return None
for name, client in self.get_instances().items():
state = client.get_state()
if not state:
return False, f"VoceChat {name} 未就续"
return True, ""
def init_setting(self) -> Tuple[str, Union[str, bool]]:
pass
def message_parser(self, source: str, body: Any, form: Any,
args: Any) -> Optional[CommingMessage]:
"""
解析消息内容,返回字典,注意以下约定值:
userid: 用户ID
username: 用户名
text: 内容
:param source: 消息来源
:param body: 请求体
:param form: 表单
:param args: 参数
:return: 渠道、消息体
"""
try:
"""
{
"created_at": 1672048481664, //消息创建的时间戳
"detail": {
"content": "hello this is my message to you", //消息内容
"content_type": "text/plain", //消息类型text/plain纯文本消息text/markdownmarkdown消息vocechat/file文件类消息
"expires_in": null, //消息过期时长如果有大于0数字说明该消息是个限时消息
"properties": null, //一些有关消息的元数据比如at信息文件消息的具体类型信息如果是个图片消息还会有一些宽高图片名称等元信息
"type": "normal" //消息类型normal代表是新消息
},
"from_uid": 7910, //来自于谁
"mid": 2978, //消息ID
"target": { "gid": 2 } //发送给谁gid代表是发送给频道uid代表是发送给个人此时的数据结构举例{"uid":1}
}
"""
# 获取服务配置
client_config = self.get_config(source)
if not client_config:
return None
# 报文体
msg_body = json.loads(body)
# 类型
msg_type = msg_body.get("detail", {}).get("type")
if msg_type != "normal":
# 非新消息
return None
logger.debug(f"收到VoceChat请求{msg_body}")
# 文本内容
content = msg_body.get("detail", {}).get("content")
# 用户ID
gid = msg_body.get("target", {}).get("gid")
channel_id = client_config.config.get("channel_id")
if gid and str(gid) == str(channel_id):
# 来自监听频道的消息
userid = f"GID#{gid}"
else:
# 来自个人的消息
userid = f"UID#{msg_body.get('from_uid')}"
# 处理消息内容
if content and userid:
logger.info(f"收到来自 {client_config.name} 的VoceChat消息userid={userid}, text={content}")
return CommingMessage(channel=MessageChannel.VoceChat, source=client_config.name,
userid=userid, username=userid, text=content)
except Exception as err:
logger.error(f"VoceChat消息处理发生错误{str(err)}")
return None
def post_message(self, message: Notification) -> None:
"""
发送消息
:param message: 消息内容
:return: 成功或失败
"""
for conf in self.get_configs().values():
if not self.check_message(message, conf.name):
continue
targets = message.targets
userid = message.userid
if not message.userid and targets:
userid = targets.get('telegram_userid')
client: VoceChat = self.get_instance(conf.name)
if client:
client.send_msg(title=message.title, text=message.text,
userid=userid, link=message.link)
def post_medias_message(self, message: Notification, medias: List[MediaInfo]) -> None:
"""
发送媒体信息选择列表
:param message: 消息内容
:param medias: 媒体列表
:return: 成功或失败
"""
for conf in self.get_configs().values():
if not self.check_message(message, conf.name):
continue
client: VoceChat = self.get_instance(conf.name)
if client:
client.send_msg(title=message.title, userid=message.userid)
client.send_medias_msg(title=message.title, medias=medias,
userid=message.userid, link=message.link)
def post_torrents_message(self, message: Notification, torrents: List[Context]) -> None:
"""
发送种子信息选择列表
:param message: 消息内容
:param torrents: 种子列表
:return: 成功或失败
"""
for conf in self.get_configs().values():
if not self.check_message(message, conf.name):
continue
targets = message.targets
userid = message.userid
if not userid and targets is not None:
userid = targets.get('vocechat_userid')
if not userid:
logger.warn(f"用户没有指定 VoceChat用户ID消息无法发送")
return
client: VoceChat = self.get_instance(conf.name)
if client:
client.send_torrents_msg(title=message.title, torrents=torrents,
userid=userid, link=message.link)
def register_commands(self, commands: Dict[str, dict]):
pass