diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..6deafc2 --- /dev/null +++ b/.flake8 @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 120 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..a5add71 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,17 @@ +repos: + - repo: https://github.com/psf/black + rev: 22.1.0 + hooks: + - id: black + + - repo: https://github.com/PyCQA/flake8 + rev: 4.0.1 + hooks: + - id: flake8 + additional_dependencies: + - flake8-bugbear + + - repo: https://github.com/PyCQA/isort + rev: 5.10.1 + hooks: + - id: isort diff --git a/efb_qq_plugin_go_cqhttp/ChatMgr.py b/efb_qq_plugin_go_cqhttp/ChatMgr.py index cca1867..ee0698a 100644 --- a/efb_qq_plugin_go_cqhttp/ChatMgr.py +++ b/efb_qq_plugin_go_cqhttp/ChatMgr.py @@ -8,95 +8,100 @@ from ehforwarderbot.types import ChatID class ChatManager: - def __init__(self, channel: 'QQMessengerChannel'): - self.channel: 'QQMessengerChannel' = channel + def __init__(self, channel: "QQMessengerChannel"): + self.channel: "QQMessengerChannel" = channel self.logger: logging.Logger = logging.getLogger(__name__) self.MISSING_GROUP: GroupChat = GroupChat( - channel=self.channel, - uid=ChatID("__error_group__"), - name="Group Missing" + channel=self.channel, uid=ChatID("__error_group__"), name="Group Missing" ) self.MISSING_CHAT: PrivateChat = PrivateChat( - channel=self.channel, - uid=ChatID("__error_chat__"), - name="Chat Missing" + channel=self.channel, uid=ChatID("__error_chat__"), name="Chat Missing" ) def build_efb_chat_as_private(self, context): - uid = context['user_id'] - if 'sender' not in context or 'nickname' not in context['sender']: + uid = context["user_id"] + if "sender" not in context or "nickname" not in context["sender"]: i: dict = self.channel.QQClient.get_stranger_info(uid) chat_name = "" if i: - chat_name = i['nickname'] + chat_name = i["nickname"] else: - chat_name = context['sender']['nickname'] - efb_chat = PrivateChat(channel=self.channel, - uid='private' + '_' + str(uid), - name=str(chat_name), - alias=None if 'alias' not in context else str(context['alias'])) + chat_name = context["sender"]["nickname"] + efb_chat = PrivateChat( + channel=self.channel, + uid="private" + "_" + str(uid), + name=str(chat_name), + alias=None if "alias" not in context else str(context["alias"]), + ) return efb_chat def build_or_get_efb_member(self, chat: Chat, context): - member_uid = context['user_id'] + member_uid = context["user_id"] with contextlib.suppress(KeyError): return chat.get_member(str(member_uid)) - chat_name = '' - if 'nickname' not in context: + chat_name = "" + if "nickname" not in context: i: dict = self.channel.QQClient.get_stranger_info(member_uid) chat_name = "" if i: - chat_name = i['nickname'] + chat_name = i["nickname"] else: - chat_name = context['nickname'] - return chat.add_member(name=str(chat_name), - alias=None if 'alias' not in context else str(context['alias']), - uid=str(member_uid)) + chat_name = context["nickname"] + return chat.add_member( + name=str(chat_name), + alias=None if "alias" not in context else str(context["alias"]), + uid=str(member_uid), + ) def build_efb_chat_as_group(self, context, update_member=False): # Should be cached - is_discuss = False if context['message_type'] == 'group' else True - chat_uid = context['discuss_id'] if is_discuss else context['group_id'] - efb_chat = GroupChat( - channel=self.channel, - uid=str(chat_uid) - ) + is_discuss = False if context["message_type"] == "group" else True + chat_uid = context["discuss_id"] if is_discuss else context["group_id"] + efb_chat = GroupChat(channel=self.channel, uid=str(chat_uid)) if not is_discuss: - efb_chat.uid = 'group' + '_' + str(chat_uid) + efb_chat.uid = "group" + "_" + str(chat_uid) i = self.channel.QQClient.get_group_info(chat_uid) if i is not None: - efb_chat.name = str(i['group_name']) if 'group_name' not in context else str(context['group_name']) + efb_chat.name = str(i["group_name"]) if "group_name" not in context else str(context["group_name"]) else: efb_chat.name = str(chat_uid) - efb_chat.vendor_specific = {'is_discuss': False} + efb_chat.vendor_specific = {"is_discuss": False} if update_member: members = self.channel.QQClient.get_group_member_list(chat_uid, False) if members: for member in members: - efb_chat.add_member(name=str(member['card']), - alias=str(member['nickname']), - uid=str(member['user_id'])) + efb_chat.add_member( + name=str(member["card"]), + alias=str(member["nickname"]), + uid=str(member["user_id"]), + ) else: - efb_chat.uid = 'discuss' + '_' + str(chat_uid) - efb_chat.name = 'Discuss Group' + '_' + str(chat_uid) + efb_chat.uid = "discuss" + "_" + str(chat_uid) + efb_chat.name = "Discuss Group" + "_" + str(chat_uid) # todo Find a way to distinguish from different discuss group - efb_chat.vendor_specific = {'is_discuss': True} + efb_chat.vendor_specific = {"is_discuss": True} return efb_chat def build_efb_chat_as_anonymous_user(self, chat: Chat, context): - anonymous_data = context['anonymous'] - member_uid = 'anonymous' + '_' + anonymous_data['flag'] + anonymous_data = context["anonymous"] + member_uid = "anonymous" + "_" + anonymous_data["flag"] with contextlib.suppress(KeyError): return chat.get_member(member_uid) - chat_name = '[Anonymous] ' + anonymous_data['name'] - return chat.add_member(name=str(chat_name), - alias=None if 'alias' not in context else str(context['alias']), - uid=str(member_uid), - vendor_specific={'is_anonymous': True, - 'anonymous_id': anonymous_data['id']}) + chat_name = "[Anonymous] " + anonymous_data["name"] + return chat.add_member( + name=str(chat_name), + alias=None if "alias" not in context else str(context["alias"]), + uid=str(member_uid), + vendor_specific={ + "is_anonymous": True, + "anonymous_id": anonymous_data["id"], + }, + ) def build_efb_chat_as_system_user(self, context): # System user only! - return SystemChat(channel=self.channel, - name=str(context['event_description']), - uid=ChatID("__{context[uid_prefix]}__".format(context=context))) + return SystemChat( + channel=self.channel, + name=str(context["event_description"]), + uid=ChatID("__{context[uid_prefix]}__".format(context=context)), + ) diff --git a/efb_qq_plugin_go_cqhttp/GoCQHttp.py b/efb_qq_plugin_go_cqhttp/GoCQHttp.py index eb8e7bb..97d363e 100644 --- a/efb_qq_plugin_go_cqhttp/GoCQHttp.py +++ b/efb_qq_plugin_go_cqhttp/GoCQHttp.py @@ -4,32 +4,52 @@ import tempfile import threading import time import uuid -from datetime import timedelta, datetime +from datetime import datetime, timedelta from gettext import translation -from typing import Any, Dict, List, BinaryIO, Tuple, Optional, Union +from typing import Any, BinaryIO, Dict, List, Optional, Tuple, Union import cherrypy import cqhttp -from PIL import Image from cherrypy._cpserver import Server from cherrypy.process.wspbus import states from cqhttp import CQHttp from efb_qq_slave import BaseClient, QQMessengerChannel -from ehforwarderbot import Message, MsgType, Chat, coordinator, Status -from ehforwarderbot.chat import SelfChatMember, ChatMember, SystemChatMember, PrivateChat -from ehforwarderbot.exceptions import EFBMessageError, EFBOperationNotSupported, EFBChatNotFound -from ehforwarderbot.message import MessageCommands, MessageCommand +from ehforwarderbot import Chat, Message, MsgType, Status, coordinator +from ehforwarderbot.chat import ( + ChatMember, + PrivateChat, + SelfChatMember, + SystemChatMember, +) +from ehforwarderbot.exceptions import ( + EFBChatNotFound, + EFBMessageError, + EFBOperationNotSupported, +) +from ehforwarderbot.message import MessageCommand, MessageCommands from ehforwarderbot.status import MessageRemoval from ehforwarderbot.types import ChatID from ehforwarderbot.utils import extra +from PIL import Image from pkg_resources import resource_filename from requests import RequestException from .ChatMgr import ChatManager -from .Exceptions import CoolQDisconnectedException, CoolQAPIFailureException, CoolQOfflineException +from .Exceptions import ( + CoolQAPIFailureException, + CoolQDisconnectedException, + CoolQOfflineException, +) from .MsgDecorator import QQMsgProcessor -from .Utils import qq_emoji_list, async_send_messages_to_master, process_quote_text, coolq_text_encode, \ - download_user_avatar, download_group_avatar, download_file +from .Utils import ( + async_send_messages_to_master, + coolq_text_encode, + download_file, + download_group_avatar, + download_user_avatar, + process_quote_text, + qq_emoji_list, +) class GoCQHttp(BaseClient): @@ -41,9 +61,11 @@ class GoCQHttp(BaseClient): logger: logging.Logger = logging.getLogger(__name__) channel: QQMessengerChannel - translator = translation("efb_qq_slave", - resource_filename('efb_qq_slave', 'Clients/CoolQ/locale'), - fallback=True) + translator = translation( + "efb_qq_slave", + resource_filename("efb_qq_slave", "Clients/CoolQ/locale"), + fallback=True, + ) _ = translator.gettext ngettext = translator.ngettext @@ -71,9 +93,10 @@ class GoCQHttp(BaseClient): def __init__(self, client_id: str, config: Dict[str, Any], channel): super().__init__(client_id, config) self.client_config = config[self.client_id] - self.coolq_bot = CQHttp(api_root=self.client_config['api_root'], - access_token=self.client_config['access_token'] - ) + self.coolq_bot = CQHttp( + api_root=self.client_config["api_root"], + access_token=self.client_config["access_token"], + ) self.channel = channel self.chat_manager = ChatManager(channel) @@ -81,59 +104,65 @@ class GoCQHttp(BaseClient): self.is_logged_in = False self.msg_decorator = QQMsgProcessor(instance=self) - def message_element_wrapper(context: Dict[str, Any], msg_element: Dict[str, Any], chat: Chat) -> \ - Tuple[str, List[Message], List[Tuple[Tuple[int, int], Union[Chat, ChatMember]]]]: - msg_type = msg_element['type'] - msg_data = msg_element['data'] - main_text: str = '' + def message_element_wrapper( + context: Dict[str, Any], msg_element: Dict[str, Any], chat: Chat + ) -> Tuple[str, List[Message], List[Tuple[Tuple[int, int], Union[Chat, ChatMember]]]]: + msg_type = msg_element["type"] + msg_data = msg_element["data"] + main_text: str = "" messages: List[Message] = [] at_list: List[Tuple[Tuple[int, int], Union[Chat, ChatMember]]] = [] - if msg_type == 'text': - main_text = msg_data['text'] - elif msg_type == 'face': - qq_face = int(msg_data['id']) + if msg_type == "text": + main_text = msg_data["text"] + elif msg_type == "face": + qq_face = int(msg_data["id"]) if qq_face in qq_emoji_list: main_text = qq_emoji_list[qq_face] else: - main_text = '\u2753' # ❓ - elif msg_type == 'sface': - main_text = '\u2753' # ❓ - elif msg_type == 'at': + main_text = "\u2753" # ❓ + elif msg_type == "sface": + main_text = "\u2753" # ❓ + elif msg_type == "at": # todo Recheck if bug exists - g_id = context['group_id'] + g_id = context["group_id"] my_uid = self.get_qq_uid() - self.logger.debug('My QQ uid: %s\n' - 'QQ mentioned: %s\n', my_uid, msg_data['qq']) - if str(msg_data['qq']) == 'all': - group_card = 'all' + self.logger.debug("My QQ uid: %s\n" "QQ mentioned: %s\n", my_uid, msg_data["qq"]) + if str(msg_data["qq"]) == "all": + group_card = "all" else: - member_info = self.get_user_info(msg_data['qq'], group_id=g_id)['in_group_info'] - group_card = member_info['card'] if member_info['card'] != '' else member_info['nickname'] - self.logger.debug('Group card: {}'.format(group_card)) + member_info = self.get_user_info(msg_data["qq"], group_id=g_id)["in_group_info"] + group_card = member_info["card"] if member_info["card"] != "" else member_info["nickname"] + self.logger.debug("Group card: {}".format(group_card)) substitution_begin = len(main_text) substitution_end = len(main_text) + len(group_card) + 1 - main_text = '@{} '.format(group_card) - if str(my_uid) == str(msg_data['qq']) or str(msg_data['qq']) == 'all': + main_text = "@{} ".format(group_card) + if str(my_uid) == str(msg_data["qq"]) or str(msg_data["qq"]) == "all": at_dict = ((substitution_begin, substitution_end), chat.self) at_list.append(at_dict) - elif msg_type == 'reply': - ref_user = self.get_user_info(msg_data['qq']) - main_text = f'「{ref_user["remark"]}({ref_user["nickname"]}):{msg_data["text"]}」\n' \ - '- - - - - - - - - - - - - - -\n' + elif msg_type == "reply": + ref_user = self.get_user_info(msg_data["qq"]) + main_text = ( + f'「{ref_user["remark"]}({ref_user["nickname"]}):{msg_data["text"]}」\n' + "- - - - - - - - - - - - - - -\n" + ) else: messages.extend(self.call_msg_decorator(msg_type, msg_data, chat)) return main_text, messages, at_list - def message_elements_wrapper(context: Dict[str, Any], msg_elements: List[Dict[str, Any]], chat: Chat) -> \ - Tuple[str, List[Message], Dict[Tuple[int, int], Union[Chat, ChatMember]]]: + def message_elements_wrapper( + context: Dict[str, Any], msg_elements: List[Dict[str, Any]], chat: Chat + ) -> Tuple[str, List[Message], Dict[Tuple[int, int], Union[Chat, ChatMember]]]: messages: List[Message] = [] - main_text: str = '' + main_text: str = "" at_dict: Dict[Tuple[int, int], Union[Chat, ChatMember]] = {} for msg_element in msg_elements: sub_main_text, sub_messages, sub_at_list = message_element_wrapper(context, msg_element, chat) main_text_len = len(main_text) for at_tuple in sub_at_list: - pos = (at_tuple[0][0] + main_text_len, at_tuple[0][1] + main_text_len) + pos = ( + at_tuple[0][0] + main_text_len, + at_tuple[0][1] + main_text_len, + ) at_dict[pos] = at_tuple[1] main_text += sub_main_text messages.extend(sub_messages) @@ -142,33 +171,33 @@ class GoCQHttp(BaseClient): @self.coolq_bot.on_message def handle_msg(context): self.logger.debug(repr(context)) - msg_elements = context['message'] - qq_uid = context['user_id'] + msg_elements = context["message"] + qq_uid = context["user_id"] chat: Chat author: ChatMember user = self.get_user_info(qq_uid) - if context['message_type'] == 'private': - context['alias'] = user['remark'] + if context["message_type"] == "private": + context["alias"] = user["remark"] chat: PrivateChat = self.chat_manager.build_efb_chat_as_private(context) else: chat = self.chat_manager.build_efb_chat_as_group(context) - if 'anonymous' not in context or context['anonymous'] is None: - if context['message_type'] == 'group': - if context['sub_type'] == 'notice': - context['event_description'] = self._("System Notification") - context['uid_prefix'] = 'group_notification' + if "anonymous" not in context or context["anonymous"] is None: + if context["message_type"] == "group": + if context["sub_type"] == "notice": + context["event_description"] = self._("System Notification") + context["uid_prefix"] = "group_notification" author = chat.add_system_member( - name=context['event_description'], - uid=ChatID("__{context[uid_prefix]}__".format(context=context)) + name=context["event_description"], + uid=ChatID("__{context[uid_prefix]}__".format(context=context)), ) else: - user = self.get_user_info(qq_uid, group_id=context['group_id']) - context['nickname'] = user['remark'] - context['alias'] = user['in_group_info']['card'] + user = self.get_user_info(qq_uid, group_id=context["group_id"]) + context["nickname"] = user["remark"] + context["alias"] = user["in_group_info"]["card"] author = self.chat_manager.build_or_get_efb_member(chat, context) - elif context['message_type'] == 'private': + elif context["message_type"] == "private": author = chat.other else: author = self.chat_manager.build_or_get_efb_member(chat, context) @@ -180,18 +209,18 @@ class GoCQHttp(BaseClient): if main_text != "": messages.append(self.msg_decorator.qq_text_simple_wrapper(main_text, at_dict)) uid: str = str(uuid.uuid4()) - coolq_msg_id = context['message_id'] + coolq_msg_id = context["message_id"] for i in range(len(messages)): if not isinstance(messages[i], Message): continue efb_msg: Message = messages[i] - efb_msg.uid = uid + '_' + str(coolq_msg_id) + '_' + str(i) + efb_msg.uid = uid + "_" + str(coolq_msg_id) + "_" + str(i) efb_msg.chat = chat efb_msg.author = author # if qq_uid != '80000000': # Append discuss group into group list - if context['message_type'] == 'discuss' and efb_msg.chat not in self.discuss_list: + if context["message_type"] == "discuss" and efb_msg.chat not in self.discuss_list: self.discuss_list.append(efb_msg.chat) efb_msg.deliver_to = coordinator.master @@ -201,170 +230,192 @@ class GoCQHttp(BaseClient): send_message_wrapper(efb_msg) - @self.coolq_bot.on_notice('group_increase') + @self.coolq_bot.on_notice("group_increase") def handle_group_increase_msg(context): - context['event_description'] = self._('\u2139 Group Member Increase Event') - if (context['sub_type']) == 'invite': - text = self._('{nickname}({context[user_id]}) joined the group({group_name}) via invitation') + context["event_description"] = self._("\u2139 Group Member Increase Event") + if (context["sub_type"]) == "invite": + text = self._("{nickname}({context[user_id]}) joined the group({group_name}) via invitation") else: - text = self._('{nickname}({context[user_id]}) joined the group({group_name})') + text = self._("{nickname}({context[user_id]}) joined the group({group_name})") - original_group = self.get_group_info(context['group_id'], False) - group_name = context['group_id'] - if original_group is not None and 'group_name' in original_group: - group_name = original_group['group_name'] - text = text.format(nickname=self.get_stranger_info(context['user_id'])['nickname'], - context=context, - group_name=group_name) + original_group = self.get_group_info(context["group_id"], False) + group_name = context["group_id"] + if original_group is not None and "group_name" in original_group: + group_name = original_group["group_name"] + text = text.format( + nickname=self.get_stranger_info(context["user_id"])["nickname"], + context=context, + group_name=group_name, + ) - context['message'] = text + context["message"] = text self.send_efb_group_notice(context) - @self.coolq_bot.on_notice('group_decrease') + @self.coolq_bot.on_notice("group_decrease") def handle_group_decrease_msg(context): - context['event_description'] = self._("\u2139 Group Member Decrease Event") - original_group = self.get_group_info(context['group_id'], False) - group_name = context['group_id'] - if original_group is not None and 'group_name' in original_group: - group_name = original_group['group_name'] - text = '' - if context['sub_type'] == 'kick_me': + context["event_description"] = self._("\u2139 Group Member Decrease Event") + original_group = self.get_group_info(context["group_id"], False) + group_name = context["group_id"] + if original_group is not None and "group_name" in original_group: + group_name = original_group["group_name"] + text = "" + if context["sub_type"] == "kick_me": text = self._("You've been kicked from the group({})").format(group_name) else: - if context['sub_type'] == 'leave': - text = self._('{nickname}({context[user_id]}) quited the group({group_name})') + if context["sub_type"] == "leave": + text = self._("{nickname}({context[user_id]}) quited the group({group_name})") else: - text = self._('{nickname}({context[user_id]}) was kicked from the group({group_name})') - text = text.format(nickname=self.get_stranger_info(context['user_id'])['nickname'], - context=context, - group_name=group_name) - context['message'] = text + text = self._("{nickname}({context[user_id]}) was kicked from the group({group_name})") + text = text.format( + nickname=self.get_stranger_info(context["user_id"])["nickname"], + context=context, + group_name=group_name, + ) + context["message"] = text self.send_efb_group_notice(context) - @self.coolq_bot.on_notice('offline_file') + @self.coolq_bot.on_notice("offline_file") def handle_offline_file_upload_msg(context): - context['event_description'] = self._("\u2139 Offline File Upload Event") - context['uid_prefix'] = 'offline_file' - file_info_msg = self._('Filename: {file[name]}\n' - 'File size: {file[size]}').format(file=context['file']) - user = self.get_user_info(context['user_id']) - text = self._('{remark}({nickname}) uploaded a file to you\n') - text = text.format(remark=user['remark'], nickname=user['nickname']) + file_info_msg - context['message'] = text + context["event_description"] = self._("\u2139 Offline File Upload Event") + context["uid_prefix"] = "offline_file" + file_info_msg = self._("Filename: {file[name]}\n" "File size: {file[size]}").format(file=context["file"]) + user = self.get_user_info(context["user_id"]) + text = self._("{remark}({nickname}) uploaded a file to you\n") + text = text.format(remark=user["remark"], nickname=user["nickname"]) + file_info_msg + context["message"] = text self.send_msg_to_master(context) param_dict = { - 'context': context, - 'download_url': context['file']['url'], + "context": context, + "download_url": context["file"]["url"], } threading.Thread(target=self.async_download_file, args=[], kwargs=param_dict).start() - @self.coolq_bot.on_notice('group_upload') + @self.coolq_bot.on_notice("group_upload") def handle_group_file_upload_msg(context): - context['event_description'] = self._("\u2139 Group File Upload Event") - context['uid_prefix'] = 'group_upload' - original_group = self.get_group_info(context['group_id'], False) - group_name = context['group_id'] - if original_group is not None and 'group_name' in original_group: - group_name = original_group['group_name'] + context["event_description"] = self._("\u2139 Group File Upload Event") + context["uid_prefix"] = "group_upload" + original_group = self.get_group_info(context["group_id"], False) + group_name = context["group_id"] + if original_group is not None and "group_name" in original_group: + group_name = original_group["group_name"] - file_info_msg = self._('File ID: {file[id]}\n' - 'Filename: {file[name]}\n' - 'File size: {file[size]}').format(file=context['file']) - member_info = self.get_user_info(context['user_id'], group_id=context['group_id'])['in_group_info'] - group_card = member_info['card'] if member_info['card'] != '' else member_info['nickname'] - text = self._('{member_card}({context[user_id]}) uploaded a file to group({group_name})\n') - text = text.format(member_card=group_card, - context=context, - group_name=group_name) + file_info_msg - context['message'] = text + file_info_msg = self._("File ID: {file[id]}\n" "Filename: {file[name]}\n" "File size: {file[size]}").format( + file=context["file"] + ) + member_info = self.get_user_info(context["user_id"], group_id=context["group_id"])["in_group_info"] + group_card = member_info["card"] if member_info["card"] != "" else member_info["nickname"] + text = self._("{member_card}({context[user_id]}) uploaded a file to group({group_name})\n") + text = text.format(member_card=group_card, context=context, group_name=group_name) + file_info_msg + context["message"] = text self.send_efb_group_notice(context) param_dict = { - 'context': context, - 'group_id': context['group_id'], - 'file_id': context['file']['id'], - 'busid': context['file']['busid'] + "context": context, + "group_id": context["group_id"], + "file_id": context["file"]["id"], + "busid": context["file"]["busid"], } threading.Thread(target=self.async_download_group_file, args=[], kwargs=param_dict).start() - @self.coolq_bot.on_notice('friend_add') + @self.coolq_bot.on_notice("friend_add") def handle_friend_add_msg(context): - context['event_description'] = self._('\u2139 New Friend Event') - context['uid_prefix'] = 'friend_add' - text = self._('{nickname}({context[user_id]}) has become your friend!') - text = text.format(nickname=self.get_stranger_info(context['user_id'])['nickname'], - context=context) - context['message'] = text + context["event_description"] = self._("\u2139 New Friend Event") + context["uid_prefix"] = "friend_add" + text = self._("{nickname}({context[user_id]}) has become your friend!") + text = text.format( + nickname=self.get_stranger_info(context["user_id"])["nickname"], + context=context, + ) + context["message"] = text self.send_msg_to_master(context) - @self.coolq_bot.on_request('friend') # Add friend request + @self.coolq_bot.on_request("friend") # Add friend request def handle_add_friend_request(context): self.logger.debug(repr(context)) - context['event_description'] = self._('\u2139 New Friend Request') - context['uid_prefix'] = 'friend_request' - text = self._('{nickname}({context[user_id]}) wants to be your friend!\n' - 'Here is the verification comment:\n' - '{context[comment]}') - text = text.format(nickname=self.get_stranger_info(context['user_id'])['nickname'], - context=context) - context['message'] = text - commands = [MessageCommand( - name=self._("Accept"), - callable_name="process_friend_request", - kwargs={'result': 'accept', - 'flag': context['flag']} - ), MessageCommand( - name=self._("Decline"), - callable_name="process_friend_request", - kwargs={'result': 'decline', - 'flag': context['flag']} - )] - context['commands'] = commands + context["event_description"] = self._("\u2139 New Friend Request") + context["uid_prefix"] = "friend_request" + text = self._( + "{nickname}({context[user_id]}) wants to be your friend!\n" + "Here is the verification comment:\n" + "{context[comment]}" + ) + text = text.format( + nickname=self.get_stranger_info(context["user_id"])["nickname"], + context=context, + ) + context["message"] = text + commands = [ + MessageCommand( + name=self._("Accept"), + callable_name="process_friend_request", + kwargs={"result": "accept", "flag": context["flag"]}, + ), + MessageCommand( + name=self._("Decline"), + callable_name="process_friend_request", + kwargs={"result": "decline", "flag": context["flag"]}, + ), + ] + context["commands"] = commands self.send_msg_to_master(context) - @self.coolq_bot.on_request('group') + @self.coolq_bot.on_request("group") def handle_group_request(context): self.logger.debug(repr(context)) - context['uid_prefix'] = 'group_request' - context['group_name'] = self._('[Request]') + self.get_group_info(context['group_id'])['group_name'] - context['group_id_orig'] = context['group_id'] - context['group_id'] = str(context['group_id']) + "_notification" - context['message_type'] = 'group' - context['event_description'] = '\u2139 New Group Join Request' - original_group = self.get_group_info(context['group_id'], False) - group_name = context['group_id'] - if original_group is not None and 'group_name' in original_group: - group_name = original_group['group_name'] + context["uid_prefix"] = "group_request" + context["group_name"] = self._("[Request]") + self.get_group_info(context["group_id"])["group_name"] + context["group_id_orig"] = context["group_id"] + context["group_id"] = str(context["group_id"]) + "_notification" + context["message_type"] = "group" + context["event_description"] = "\u2139 New Group Join Request" + original_group = self.get_group_info(context["group_id"], False) + group_name = context["group_id"] + if original_group is not None and "group_name" in original_group: + group_name = original_group["group_name"] msg = Message() - msg.uid = 'group' + '_' + str(context['group_id']) + msg.uid = "group" + "_" + str(context["group_id"]) msg.author = self.chat_manager.build_efb_chat_as_system_user(context) msg.chat = self.chat_manager.build_efb_chat_as_group(context) msg.deliver_to = coordinator.master msg.type = MsgType.Text name = "" - if not self.get_friend_remark(context['user_id']): + if not self.get_friend_remark(context["user_id"]): name = "{}({})[{}] ".format( - self.get_stranger_info(context['user_id'])['nickname'], self.get_friend_remark(context['user_id']), - context['user_id']) + self.get_stranger_info(context["user_id"])["nickname"], + self.get_friend_remark(context["user_id"]), + context["user_id"], + ) else: - name = "{}[{}] ".format(self.get_stranger_info(context['user_id'])['nickname'], context['user_id']) + name = "{}[{}] ".format( + self.get_stranger_info(context["user_id"])["nickname"], + context["user_id"], + ) msg.text = "{} wants to join the group {}({}). \nHere is the comment: {}".format( - name, group_name, context['group_id_orig'], context['comment'] + name, group_name, context["group_id_orig"], context["comment"] + ) + msg.commands = MessageCommands( + [ + MessageCommand( + name=self._("Accept"), + callable_name="process_group_request", + kwargs={ + "result": "accept", + "flag": context["flag"], + "sub_type": context["sub_type"], + }, + ), + MessageCommand( + name=self._("Decline"), + callable_name="process_group_request", + kwargs={ + "result": "decline", + "flag": context["flag"], + "sub_type": context["sub_type"], + }, + ), + ] ) - msg.commands = MessageCommands([MessageCommand( - name=self._("Accept"), - callable_name="process_group_request", - kwargs={'result': 'accept', - 'flag': context['flag'], - 'sub_type': context['sub_type']} - ), MessageCommand( - name=self._("Decline"), - callable_name="process_group_request", - kwargs={'result': 'decline', - 'flag': context['flag'], - 'sub_type': context['sub_type']} - )]) coordinator.send_message(msg) self.check_status_periodically(threading.Event()) @@ -377,46 +428,51 @@ class GoCQHttp(BaseClient): cherrypy.tree.graft(self.coolq_bot.wsgi, "/") cherrypy.server.unsubscribe() self.cherryServer = Server() - self.cherryServer.socket_host = self.client_config['host'] - self.cherryServer.socket_port = self.client_config['port'] + self.cherryServer.socket_host = self.client_config["host"] + self.cherryServer.socket_port = self.client_config["port"] self.cherryServer.subscribe() cherrypy.engine.start() cherrypy.engine.wait(states.EXITING) - @extra(name=_("Restart CoolQ Client"), - desc=_("Force CoolQ to restart\n" - "Usage: {function_name} [-l] [-c] [-e]\n" - " -l: Restart and clean log\n" - " -c: Restart and clean cache\n" - " -e: Restart and clean event\n")) + @extra( + name=_("Restart CoolQ Client"), + desc=_( + "Force CoolQ to restart\n" + "Usage: {function_name} [-l] [-c] [-e]\n" + " -l: Restart and clean log\n" + " -c: Restart and clean cache\n" + " -e: Restart and clean event\n" + ), + ) def relogin(self, param: str = ""): param_dict = dict() if param: - params = param.split(' ') + params = param.split(" ") for each_param in params: - if each_param == ' ': + if each_param == " ": continue - if each_param == '-l': - param_dict['clean_log'] = 'true' - elif each_param == '-c': - param_dict['clean_cache'] = 'true' - elif each_param == '-e': - param_dict['clean_event'] = 'true' + if each_param == "-l": + param_dict["clean_log"] = "true" + elif each_param == "-c": + param_dict["clean_cache"] = "true" + elif each_param == "-e": + param_dict["clean_event"] = "true" else: return self._("Unknown parameter: {}.").format(param) self.logger.debug(repr(param_dict)) - self.coolq_api_query('_set_restart', **param_dict) - return 'Done. Please wait for a while.' + self.coolq_api_query("_set_restart", **param_dict) + return "Done. Please wait for a while." def logout(self): raise NotImplementedError - @extra(name=_("Check CoolQ Status"), - desc=_("Force efb-qq-slave to refresh status from CoolQ Client.\n" - "Usage: {function_name}")) + @extra( + name=_("Check CoolQ Status"), + desc=_("Force efb-qq-slave to refresh status from CoolQ Client.\n" "Usage: {function_name}"), + ) def login(self, param: str = ""): self.check_status_periodically(None) - return 'Done' + return "Done" def get_stranger_info(self, user_id: int, no_cache: bool = False) -> Dict[str, Any]: user_id = int(user_id) @@ -424,11 +480,14 @@ class GoCQHttp(BaseClient): def get_login_info(self) -> Dict[Any, Any]: res = self.coolq_bot.get_status() - if 'good' in res or 'online' in res: + if "good" in res or "online" in res: data = self.coolq_bot.get_login_info() - return {'status': 0, 'data': {'uid': data['user_id'], 'nickname': data['nickname']}} + return { + "status": 0, + "data": {"uid": data["user_id"], "nickname": data["nickname"]}, + } else: - return {'status': 1} + return {"status": 1} def get_groups(self) -> List: # todo Add support for discuss group iteration @@ -437,20 +496,21 @@ class GoCQHttp(BaseClient): # res = self.coolq_bot.get_group_list() groups = [] for i in range(len(res)): - context = {'message_type': 'group', - 'group_id': res[i]['group_id']} + context = {"message_type": "group", "group_id": res[i]["group_id"]} efb_chat = self.chat_manager.build_efb_chat_as_group(context) groups.append(efb_chat) for i in range(len(self.extra_group_list)): does_exist = False - for j in range(len(res)): - if str(self.extra_group_list[i]['group_id']) == str(res[i]['group_id']): + for _j in range(len(res)): + if str(self.extra_group_list[i]["group_id"]) == str(res[i]["group_id"]): does_exist = True break if does_exist: continue - context = {'message_type': 'group', - 'group_id': self.extra_group_list[i]['group_id']} + context = { + "message_type": "group", + "group_id": self.extra_group_list[i]["group_id"], + } efb_chat = self.chat_manager.build_efb_chat_as_group(context) groups.append(efb_chat) return groups + self.discuss_list @@ -459,14 +519,15 @@ class GoCQHttp(BaseClient): try: self.update_friend_list() # Force update friend list except CoolQAPIFailureException: - self.deliver_alert_to_master(self._('Failed to retrieve the friend list.\n' - 'Only groups are shown.')) + self.deliver_alert_to_master(self._("Failed to retrieve the friend list.\n" "Only groups are shown.")) return [] users = [] for current_user in self.friend_list: - context = {'user_id': str(current_user['user_id']), - 'nickname': current_user['nickname'], - 'alias': current_user['remark']} + context = { + "user_id": str(current_user["user_id"]), + "nickname": current_user["nickname"], + "alias": current_user["remark"], + } efb_chat = self.chat_manager.build_efb_chat_as_private(context) users.append(efb_chat) return users @@ -475,7 +536,7 @@ class GoCQHttp(BaseClient): # Replaced by handle_msg() pass - def send_message(self, msg: 'Message') -> 'Message': + def send_message(self, msg: "Message") -> "Message": # todo Add support for edited message """ self.logger.info("[%s] Sending message to WeChat:\n" @@ -488,43 +549,47 @@ class GoCQHttp(BaseClient): msg.chat.chat_uid, msg.type, msg.text, repr(msg.target.chat), msg.target.uid) """ m = QQMsgProcessor(instance=self) - chat_type = msg.chat.uid.split('_') + chat_type = msg.chat.uid.split("_") - self.logger.debug('[%s] Is edited: %s', msg.uid, msg.edit) + self.logger.debug("[%s] Is edited: %s", msg.uid, msg.edit) if msg.edit: try: - uid_type = msg.uid.split('_') + uid_type = msg.uid.split("_") self.recall_message(uid_type[1]) except CoolQAPIFailureException: - raise EFBOperationNotSupported(self._("Failed to recall the message!\n" - "This message may have already expired.")) + raise EFBOperationNotSupported( + self._("Failed to recall the message!\n" "This message may have already expired.") + ) if msg.type in [MsgType.Text, MsgType.Link]: if msg.text == "kick`": group_id = chat_type[1] user_id = msg.target.author.uid - self.coolq_api_query("set_group_kick", - group_id=group_id, - user_id=user_id) + self.coolq_api_query("set_group_kick", group_id=group_id, user_id=user_id) else: if isinstance(msg.target, Message): max_length = 50 tgt_text = coolq_text_encode(process_quote_text(msg.target.text, max_length)) tgt_alias = "" - if chat_type[0] != 'private' and not isinstance(msg.target.author, SelfChatMember): + if chat_type[0] != "private" and not isinstance(msg.target.author, SelfChatMember): tgt_alias += m.coolq_code_at_wrapper(msg.target.author.uid) else: tgt_alias = "" - msg.text = "%s%s\n\n%s" % (tgt_alias, tgt_text, coolq_text_encode(msg.text)) + msg.text = "%s%s\n\n%s" % ( + tgt_alias, + tgt_text, + coolq_text_encode(msg.text), + ) msg.uid = self.coolq_send_message(chat_type[0], chat_type[1], msg.text) - self.logger.debug('[%s] Sent as a text message. %s', msg.uid, msg.text) + self.logger.debug("[%s] Sent as a text message. %s", msg.uid, msg.text) elif msg.type in (MsgType.Image, MsgType.Sticker, MsgType.Animation): self.logger.info("[%s] Image/Sticker/Animation %s", msg.uid, msg.type) - text = '' + text = "" if not self.can_send_image: self.check_features() # Force checking features - raise EFBOperationNotSupported(self._("Unable to send image now. Please check your CoolQ version " - "or retry later")) + raise EFBOperationNotSupported( + self._("Unable to send image now. Please check your CoolQ version " "or retry later") + ) if msg.type != MsgType.Sticker: text += m.coolq_code_image_wrapper(msg.file, msg.path) else: @@ -535,7 +600,7 @@ class GoCQHttp(BaseClient): mask = Image.eval(alpha, lambda a: 255 if a <= 128 else 0) except IndexError: mask = Image.eval(img.split()[0], lambda a: 0) - img = img.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255) + img = img.convert("RGB").convert("P", palette=Image.ADAPTIVE, colors=255) img.paste(255, mask) img.save(f, transparency=255) msg.file.close() @@ -549,8 +614,12 @@ class GoCQHttp(BaseClient): elif msg.type is MsgType.Voice: if not self.can_send_voice: self.check_features() # Force checking features - raise EFBOperationNotSupported(self._("Unable to send voice now. Please check your CoolQ version " - " and install CoolQ audio library or retry later")) + raise EFBOperationNotSupported( + self._( + "Unable to send voice now. Please check your CoolQ version " + " and install CoolQ audio library or retry later" + ) + ) text = m.coolq_voice_image_wrapper(msg.file, msg.path) msg.uid = self.coolq_send_message(chat_type[0], chat_type[1], text) if msg.text: @@ -559,7 +628,7 @@ class GoCQHttp(BaseClient): def call_msg_decorator(self, msg_type: str, *args) -> List[Message]: try: - func = getattr(self.msg_decorator, 'qq_{}_wrapper'.format(msg_type)) + func = getattr(self.msg_decorator, "qq_{}_wrapper".format(msg_type)) except AttributeError: msg = f"Unsupported message type: {msg_type}" self.logger.error(msg) @@ -569,24 +638,27 @@ class GoCQHttp(BaseClient): def get_qq_uid(self): res = self.get_login_info() - if res['status'] == 0: - return res['data']['uid'] + if res["status"] == 0: + return res["data"]["uid"] else: return None def get_group_member_list(self, group_id, no_cache=False) -> List[Dict[str, Any]]: - if no_cache or (group_id not in self.group_member_dict) \ - or (datetime.now() - self.group_member_dict[group_id]['time'] > timedelta(hours=1)): # Force Update + if ( + no_cache + or (group_id not in self.group_member_dict) + or (datetime.now() - self.group_member_dict[group_id]["time"] > timedelta(hours=1)) + ): # Force Update try: - member_list = self.coolq_api_query('get_group_member_list', group_id=group_id, no_cache=no_cache) + member_list = self.coolq_api_query("get_group_member_list", group_id=group_id, no_cache=no_cache) except CoolQAPIFailureException as e: self.deliver_alert_to_master(self._("Failed the get group member detail.") + "{}".format(e)) return [] self.group_member_dict[group_id] = { - 'members': member_list, - 'time': datetime.now() + "members": member_list, + "time": datetime.now(), } - return self.group_member_dict[group_id]['members'] + return self.group_member_dict[group_id]["members"] def get_user_info(self, user_id: int, group_id: Optional[str] = None, no_cache=False): user_id = int(user_id) @@ -595,23 +667,23 @@ class GoCQHttp(BaseClient): friend = copy.deepcopy(self.friend_dict.get(user_id)) if friend: user = friend - user['is_friend'] = True + user["is_friend"] = True else: user = copy.deepcopy(self.stranger_dict.get(user_id)) if no_cache or (user is None): - user = self.coolq_api_query('get_stranger_info', user_id=user_id) + user = self.coolq_api_query("get_stranger_info", user_id=user_id) self.stranger_dict[user_id] = copy.deepcopy(user) - user['is_friend'] = False + user["is_friend"] = False if group_id is not None: - user['is_in_group'] = False + user["is_in_group"] = False for member in self.get_group_member_list(group_id): - if member['user_id'] == user_id: - user['is_in_group'] = True - user['in_group_info'] = member + if member["user_id"] == user_id: + user["is_in_group"] = True + user["in_group_info"] = member break - remark = user.get('remark') + remark = user.get("remark") if not remark: - user['remark'] = user['nickname'] + user["remark"] = user["nickname"] return user def get_group_info(self, group_id, no_cache=False): @@ -622,78 +694,88 @@ class GoCQHttp(BaseClient): return group if no_cache: for extra_group in self.extra_group_list: - if extra_group['group_id'] == group_id: + if extra_group["group_id"] == group_id: return extra_group try: external_group = self.get_external_group_info(group_id) except CoolQAPIFailureException: - self.logger.error(f'Get external group({group_id}) info failed.') + self.logger.error(f"Get external group({group_id}) info failed.") return None else: self.extra_group_list.append(external_group) return external_group def coolq_send_message(self, msg_type, uid, message): - keyword = msg_type if msg_type != 'private' else 'user' - res = self.coolq_api_query('send_msg', message_type=msg_type, **{keyword + '_id': uid}, message=message) - return str(uuid.uuid4()) + '_' + str(res['message_id']) + keyword = msg_type if msg_type != "private" else "user" + res = self.coolq_api_query("send_msg", message_type=msg_type, **{keyword + "_id": uid}, message=message) + return str(uuid.uuid4()) + "_" + str(res["message_id"]) def _coolq_api_wrapper(self, func_name, **kwargs): try: func = getattr(self.coolq_bot, func_name) res = func(**kwargs) except RequestException as e: - raise CoolQDisconnectedException(self._('Unable to connect to CoolQ Client!' - 'Error Message:\n{}').format(str(e))) + raise CoolQDisconnectedException( + self._("Unable to connect to CoolQ Client!" "Error Message:\n{}").format(str(e)) + ) except cqhttp.Error as ex: - api_ex = CoolQAPIFailureException(self._('CoolQ HTTP API encountered an error!\n' - 'Status Code:{} ' - 'Return Code:{}').format(ex.status_code, ex.retcode)) - setattr(api_ex, 'status_code', ex.status_code) - setattr(api_ex, 'retcode', ex.retcode) + api_ex = CoolQAPIFailureException( + self._("CoolQ HTTP API encountered an error!\n" "Status Code:{} " "Return Code:{}").format( + ex.status_code, ex.retcode + ) + ) + api_ex.status_code = ex.status_code + api_ex.retcode = ex.retcode raise api_ex else: return res def check_running_status(self): - res = self._coolq_api_wrapper('get_status') - if res['good'] or res['online']: + res = self._coolq_api_wrapper("get_status") + if res["good"] or res["online"]: return True else: raise CoolQOfflineException(self._("CoolQ Client isn't working correctly!")) def coolq_api_query(self, func_name, **kwargs): - """ # Do not call get_status too frequently + """# Do not call get_status too frequently if self.check_running_status(): return self._coolq_api_wrapper(func_name, **kwargs) """ if self.is_logged_in and self.is_connected: return self._coolq_api_wrapper(func_name, **kwargs) elif self.repeat_counter < 3: - self.deliver_alert_to_master(self._('Your status is offline.\n' - 'You may try login with /0_login')) + self.deliver_alert_to_master(self._("Your status is offline.\n" "You may try login with /0_login")) self.repeat_counter += 1 def check_status_periodically(self, t_event): - self.logger.debug('Start checking status...') + self.logger.debug("Start checking status...") flag = True interval = 300 try: flag = self.check_running_status() except CoolQDisconnectedException as e: if self.repeat_counter < 3: - self.deliver_alert_to_master(self._("We're unable to communicate with CoolQ Client.\n" - "Please check the connection and credentials provided.\n" - "{}").format(str(e))) + self.deliver_alert_to_master( + self._( + "We're unable to communicate with CoolQ Client.\n" + "Please check the connection and credentials provided.\n" + "{}" + ).format(str(e)) + ) self.repeat_counter += 1 self.is_connected = False self.is_logged_in = False interval = 3600 except (CoolQOfflineException, CoolQAPIFailureException): if self.repeat_counter < 3: - self.deliver_alert_to_master(self._('CoolQ is running in abnormal status.\n' - 'You may need to relogin your account ' - 'or have a check in CoolQ Client.\n')) + self.deliver_alert_to_master( + self._( + "CoolQ is running in abnormal status.\n" + "You may need to relogin your account " + "or have a check in CoolQ Client.\n" + ) + ) self.repeat_counter += 1 self.is_connected = True self.is_logged_in = False @@ -701,15 +783,19 @@ class GoCQHttp(BaseClient): else: if not flag: if self.repeat_counter < 3: - self.deliver_alert_to_master(self._("We don't know why, but status check failed.\n" - "Please enable debug mode and consult the log " - "for more details.")) + self.deliver_alert_to_master( + self._( + "We don't know why, but status check failed.\n" + "Please enable debug mode and consult the log " + "for more details." + ) + ) self.repeat_counter += 1 self.is_connected = True self.is_logged_in = False interval = 3600 else: - self.logger.debug('Status: OK') + self.logger.debug("Status: OK") self.is_connected = True self.is_logged_in = True self.repeat_counter = 0 @@ -719,47 +805,49 @@ class GoCQHttp(BaseClient): self.check_status_timer.start() def deliver_alert_to_master(self, message: str): - context = {'message': message, 'uid_prefix': 'alert', 'event_description': self._('CoolQ Alert')} + context = { + "message": message, + "uid_prefix": "alert", + "event_description": self._("CoolQ Alert"), + } self.send_msg_to_master(context) def update_friend_list(self): - self.friend_list = self.coolq_api_query('get_friend_list') + self.friend_list = self.coolq_api_query("get_friend_list") if self.friend_list: - self.logger.debug('Update friend list completed. Entries: %s', len(self.friend_list)) + self.logger.debug("Update friend list completed. Entries: %s", len(self.friend_list)) for friend in self.friend_list: - if friend['remark'] == '': - friend['remark'] = friend['nickname'] - self.friend_dict[friend['user_id']] = friend + if friend["remark"] == "": + friend["remark"] = friend["nickname"] + self.friend_dict[friend["user_id"]] = friend else: - self.logger.warning('Failed to update friend list') + self.logger.warning("Failed to update friend list") def update_group_list(self): - self.group_list = self.coolq_api_query('get_group_list') + self.group_list = self.coolq_api_query("get_group_list") if self.group_list: - self.logger.debug('Update group list completed. Entries: %s', len(self.group_list)) + self.logger.debug("Update group list completed. Entries: %s", len(self.group_list)) for group in self.group_list: - self.group_dict[group['group_id']] = group + self.group_dict[group["group_id"]] = group else: - self.logger.warning('Failed to update group list') + self.logger.warning("Failed to update group list") def update_contacts_periodically(self, t_event): - self.logger.debug('Start updating friend & group list') + self.logger.debug("Start updating friend & group list") interval = 1800 if self.is_connected and self.is_logged_in: try: self.update_friend_list() self.update_group_list() except CoolQAPIFailureException as ex: - if getattr(ex, 'status_code') == 200 and getattr(ex, 'retcode') == 104 \ - and self.update_repeat_counter < 3: + if (ex.status_code) == 200 and (ex.retcode) == 104 and self.update_repeat_counter < 3: self.send_cookie_expired_alarm() if self.update_repeat_counter < 3: - self.deliver_alert_to_master(self._('Errors occurred when updating contacts: ') - + getattr(ex, 'message')) + self.deliver_alert_to_master(self._("Errors occurred when updating contacts: ") + (ex.message)) self.update_repeat_counter += 1 else: self.update_repeat_counter = 0 - self.logger.debug('Update completed') + self.logger.debug("Update completed") if t_event is not None and not t_event.is_set(): self.update_contacts_timer = threading.Timer(interval, self.update_contacts_periodically, [t_event]) self.update_contacts_timer.start() @@ -769,10 +857,10 @@ class GoCQHttp(BaseClient): self.update_friend_list() if uid not in self.friend_dict: return None # I don't think you have such a friend - return self.friend_dict[uid]['remark'] + return self.friend_dict[uid]["remark"] def send_efb_group_notice(self, context): - context['message_type'] = 'group' + context["message_type"] = "group" self.logger.debug(repr(context)) chat = self.chat_manager.build_efb_chat_as_group(context) try: @@ -784,125 +872,116 @@ class GoCQHttp(BaseClient): type=MsgType.Text, chat=chat, author=author, - text=context['message'], - deliver_to=coordinator.master + text=context["message"], + deliver_to=coordinator.master, ) coordinator.send_message(msg) def send_msg_to_master(self, context): self.logger.debug(repr(context)) - if not getattr(coordinator, 'master', None): # Master Channel not initialized - raise Exception(context['message']) + if not getattr(coordinator, "master", None): # Master Channel not initialized + raise Exception(context["message"]) chat = self.chat_manager.build_efb_chat_as_system_user(context) try: author = chat.get_member(SystemChatMember.SYSTEM_ID) except KeyError: author = chat.add_system_member() msg = Message( - uid="__{context[uid_prefix]}__.{uni_id}".format(context=context, - uni_id=str(int(time.time()))), + uid="__{context[uid_prefix]}__.{uni_id}".format(context=context, uni_id=str(int(time.time()))), type=MsgType.Text, chat=chat, author=author, - deliver_to=coordinator.master + deliver_to=coordinator.master, ) - if 'message' in context: - msg.text = context['message'] - if 'commands' in context: - msg.commands = MessageCommands(context['commands']) + if "message" in context: + msg.text = context["message"] + if "commands" in context: + msg.commands = MessageCommands(context["commands"]) coordinator.send_message(msg) # As the old saying goes # A programmer spent 20% of time on coding # while the rest 80% on considering a variable/function/class name def get_external_group_info(self, group_id): # Special thanks to @lwl12 for thinking of this name - res = self.coolq_api_query('get_group_info', group_id=group_id) + res = self.coolq_api_query("get_group_info", group_id=group_id) return res - def send_status(self, status: 'Status'): + def send_status(self, status: "Status"): if isinstance(status, MessageRemoval): if not isinstance(status.message.author, SelfChatMember): - raise EFBMessageError(self._('You can only recall your own messages.')) + raise EFBMessageError(self._("You can only recall your own messages.")) try: - uid_type = status.message.uid.split('_') + uid_type = status.message.uid.split("_") self.recall_message(uid_type[1]) except CoolQAPIFailureException: - raise EFBMessageError( - self._('Failed to recall the message. This message may have already expired.')) + raise EFBMessageError(self._("Failed to recall the message. This message may have already expired.")) else: raise EFBOperationNotSupported() # todo def recall_message(self, message_id): - self.coolq_api_query('delete_msg', - message_id=message_id) + self.coolq_api_query("delete_msg", message_id=message_id) def send_cookie_expired_alarm(self): - self.deliver_alert_to_master(self._('Your cookie of CoolQ Client seems to be expired. ' - 'Although it will not affect the normal functioning of sending/receiving ' - 'messages, however, you may encounter issues like failing to retrieve ' - 'friend list. Please consult ' - 'https://github.com/milkice233/efb-qq-slave/wiki/Workaround-for-expired' - '-cookies-of-CoolQ for solutions.')) + self.deliver_alert_to_master( + self._( + "Your cookie of CoolQ Client seems to be expired. " + "Although it will not affect the normal functioning of sending/receiving " + "messages, however, you may encounter issues like failing to retrieve " + "friend list. Please consult " + "https://github.com/milkice233/efb-qq-slave/wiki/Workaround-for-expired" + "-cookies-of-CoolQ for solutions." + ) + ) def process_friend_request(self, result, flag): - res = 'true' if result == 'accept' else 'false' + res = "true" if result == "accept" else "false" try: - self.coolq_api_query('set_friend_add_request', - approve=res, - flag=flag) + self.coolq_api_query("set_friend_add_request", approve=res, flag=flag) except CoolQAPIFailureException as e: - return (self._('Failed to process request! Error Message:\n') - + getattr(e, 'message', repr(e))) - return 'Done' + return self._("Failed to process request! Error Message:\n") + getattr(e, "message", repr(e)) + return "Done" def process_group_request(self, result, flag, sub_type): - res = 'true' if result == 'accept' else 'false' + res = "true" if result == "accept" else "false" try: - self.coolq_api_query('set_group_add_request', - approve=res, - flag=flag, - sub_type=sub_type) + self.coolq_api_query("set_group_add_request", approve=res, flag=flag, sub_type=sub_type) except CoolQAPIFailureException as e: - return (self._('Failed to process request! Error Message:\n') - + getattr(e, 'message', repr(e))) - return 'Done' + return self._("Failed to process request! Error Message:\n") + getattr(e, "message", repr(e)) + return "Done" def async_download_file(self, context, download_url): res = download_file(download_url) if isinstance(res, str): - context['message'] = self._("[Download] ") + res + context["message"] = self._("[Download] ") + res self.send_efb_group_notice(context) elif res is None: pass else: - data = {'file': res, 'filename': context['file']['name']} - context['message_type'] = 'group' + data = {"file": res, "filename": context["file"]["name"]} + context["message_type"] = "group" efb_msg = self.msg_decorator.qq_file_after_wrapper(data) - efb_msg.uid = str(context['user_id']) + '_' + str(uuid.uuid4()) + '_' + str(1) - efb_msg.text = 'Sent a file\n{}'.format(context['file']['name']) - if context['uid_prefix'] == 'offline_file': + efb_msg.uid = str(context["user_id"]) + "_" + str(uuid.uuid4()) + "_" + str(1) + efb_msg.text = "Sent a file\n{}".format(context["file"]["name"]) + if context["uid_prefix"] == "offline_file": efb_msg.chat = self.chat_manager.build_efb_chat_as_private(context) - elif context['uid_prefix'] == 'group_upload': + elif context["uid_prefix"] == "group_upload": efb_msg.chat = self.chat_manager.build_efb_chat_as_group(context) efb_msg.author = self.chat_manager.build_or_get_efb_member(efb_msg.chat, context) efb_msg.deliver_to = coordinator.master async_send_messages_to_master(efb_msg) def async_download_group_file(self, context, group_id, file_id, busid): - file = self.coolq_api_query('get_group_file_url', - group_id=group_id, - file_id=file_id, - busid=busid) - download_url = file['url'] + file = self.coolq_api_query("get_group_file_url", group_id=group_id, file_id=file_id, busid=busid) + download_url = file["url"] self.async_download_file(context, download_url) - def get_chat_picture(self, chat: 'Chat') -> BinaryIO: - chat_type = chat.uid.split('_') - if chat_type[0] == 'private': + def get_chat_picture(self, chat: "Chat") -> BinaryIO: + chat_type = chat.uid.split("_") + if chat_type[0] == "private": return download_user_avatar(chat_type[1]) - elif chat_type[0] == 'group': + elif chat_type[0] == "group": return download_group_avatar(chat_type[1]) else: return download_group_avatar("") @@ -912,23 +991,23 @@ class GoCQHttp(BaseClient): group_chats = self.get_groups() return qq_chats + group_chats - def get_chat(self, chat_uid: ChatID) -> 'Chat': + def get_chat(self, chat_uid: ChatID) -> "Chat": # todo what is member_uid used for? - chat_type = chat_uid.split('_') - if chat_type[0] == 'private': + chat_type = chat_uid.split("_") + if chat_type[0] == "private": qq_uid = int(chat_type[1]) remark = self.get_friend_remark(qq_uid) context = {"user_id": qq_uid} if remark is not None: - context['alias'] = remark + context["alias"] = remark return self.chat_manager.build_efb_chat_as_private(context) - elif chat_type[0] == 'group': + elif chat_type[0] == "group": group_id = int(chat_type[1]) - context = {'message_type': 'group', 'group_id': group_id} + context = {"message_type": "group", "group_id": group_id} return self.chat_manager.build_efb_chat_as_group(context, update_member=True) - elif chat_type[0] == 'discuss': + elif chat_type[0] == "discuss": discuss_id = int(chat_type[1]) - context = {'message_type': 'discuss', 'discuss_id': discuss_id} + context = {"message_type": "discuss", "discuss_id": discuss_id} return self.chat_manager.build_efb_chat_as_group(context) raise EFBChatNotFound() @@ -936,10 +1015,11 @@ class GoCQHttp(BaseClient): interval = 60 * 60 * 24 latest_version = self.channel.check_updates() if latest_version is not None: - self.deliver_alert_to_master("New version({version}) of EFB-QQ-Slave has released! " - "Please manually update EQS by stopping ehForwarderbot first and then execute " - "pip3 install --upgrade efb-qq-slave" - .format(version=latest_version)) + self.deliver_alert_to_master( + "New version({version}) of EFB-QQ-Slave has released! " + "Please manually update EQS by stopping ehForwarderbot first and then execute " + "pip3 install --upgrade efb-qq-slave".format(version=latest_version) + ) else: if t_event is not None and not t_event.is_set(): self.self_update_timer = threading.Timer(interval, self.check_self_update, [t_event]) @@ -947,7 +1027,11 @@ class GoCQHttp(BaseClient): def poll(self): self.check_self_update(threading.Event()) - self.run_instance(host=self.client_config['host'], port=self.client_config['port'], debug=False) + self.run_instance( + host=self.client_config["host"], + port=self.client_config["port"], + debug=False, + ) self.logger.debug("EQS gracefully shut down") def stop_polling(self): @@ -957,5 +1041,5 @@ class GoCQHttp(BaseClient): cherrypy.engine.exit() def check_features(self): - self.can_send_image = self.coolq_api_query('can_send_image')['yes'] - self.can_send_voice = self.coolq_api_query('can_send_record')['yes'] + self.can_send_image = self.coolq_api_query("can_send_image")["yes"] + self.can_send_voice = self.coolq_api_query("can_send_record")["yes"] diff --git a/efb_qq_plugin_go_cqhttp/MsgDecorator.py b/efb_qq_plugin_go_cqhttp/MsgDecorator.py index f23ae29..2f42d51 100644 --- a/efb_qq_plugin_go_cqhttp/MsgDecorator.py +++ b/efb_qq_plugin_go_cqhttp/MsgDecorator.py @@ -2,13 +2,14 @@ import base64 import html import json import logging +import sys import magic -from ehforwarderbot import Message, MsgType, Chat -from ehforwarderbot.message import LocationAttribute, LinkAttribute, Substitutions +from ehforwarderbot import Chat, Message, MsgType +from ehforwarderbot.message import LinkAttribute, LocationAttribute, Substitutions from . import GoCQHttp -from .Utils import cq_get_image, download_voice, download_file +from .Utils import cq_get_image, download_file, download_voice class QQMsgProcessor: @@ -22,23 +23,23 @@ class QQMsgProcessor: def qq_image_wrapper(self, data, chat: Chat = None): efb_msg = Message() - if 'url' not in data: + if "url" not in data: efb_msg.type = MsgType.Text - efb_msg.text = self._('[Image Source missing]') + efb_msg.text = self._("[Image Source missing]") return [efb_msg] - efb_msg.file = cq_get_image(data['url']) + efb_msg.file = cq_get_image(data["url"]) if efb_msg.file is None: efb_msg.type = MsgType.Text - efb_msg.text = self._('[Download image failed, please check on your QQ client]') + efb_msg.text = self._("[Download image failed, please check on your QQ client]") return [efb_msg] efb_msg.type = MsgType.Image mime = magic.from_file(efb_msg.file.name, mime=True) if isinstance(mime, bytes): mime = mime.decode() - efb_msg.filename = data['file'] if 'file' in data else efb_msg.file.name - efb_msg.filename += '.' + str(mime).split('/')[1] + efb_msg.filename = data["file"] if "file" in data else efb_msg.file.name + efb_msg.filename += "." + str(mime).split("/")[1] efb_msg.path = efb_msg.file.name efb_msg.mime = mime if "gif" in mime: @@ -48,11 +49,13 @@ class QQMsgProcessor: def qq_record_wrapper(self, data, chat: Chat = None): # Experimental! efb_msg = Message() try: - transformed_file = self.inst.coolq_api_query("get_record", file=data['file'], out_format='mp3') + transformed_file = self.inst.coolq_api_query("get_record", file=data["file"], out_format="mp3") efb_msg.type = MsgType.Audio - efb_msg.file = download_voice(transformed_file['file'], - self.inst.client_config['api_root'].rstrip("/"), - self.inst.client_config['access_token']) + efb_msg.file = download_voice( + transformed_file["file"], + self.inst.client_config["api_root"].rstrip("/"), + self.inst.client_config["access_token"], + ) mime = magic.from_file(efb_msg.file.name, mime=True) if isinstance(mime, bytes): mime = mime.decode() @@ -60,52 +63,48 @@ class QQMsgProcessor: efb_msg.mime = mime except Exception: efb_msg.type = MsgType.Unsupported - efb_msg.text = self._('[Voice Message] Please check it on your QQ') + efb_msg.text = self._("[Voice Message] Please check it on your QQ") logging.getLogger(__name__).exception("Failed to download voice") return [efb_msg] def qq_share_wrapper(self, data, chat: Chat = None): efb_msg = Message( type=MsgType.Link, - text='', + text="", attributes=LinkAttribute( - title='' if 'title' not in data else data['title'], - description='' if 'content' not in data else data['content'], - image='' if 'image' not in data else data['image'], - url=data['url'] - ) + title="" if "title" not in data else data["title"], + description="" if "content" not in data else data["content"], + image="" if "image" not in data else data["image"], + url=data["url"], + ), ) return [efb_msg] def qq_location_wrapper(self, data, chat: Chat = None): efb_msg = Message( - text=data['content'], + text=data["content"], type=MsgType.Location, - attributes=LocationAttribute(longitude=float(data['lon']), - latitude=float(data['lat'])) + attributes=LocationAttribute(longitude=float(data["lon"]), latitude=float(data["lat"])), ) return [efb_msg] def qq_shake_wrapper(self, data, chat: Chat = None): - efb_msg = Message( - type=MsgType.Text, - text=self._('[Your friend shakes you!]') - ) + efb_msg = Message(type=MsgType.Text, text=self._("[Your friend shakes you!]")) return [efb_msg] def qq_contact_wrapper(self, data, chat: Chat = None): - uid = data['id'] - contact_type = data['type'] + uid = data["id"] + contact_type = data["type"] efb_msg = Message( type=MsgType.Text, - text=self._("Chat Recommendation Received\nID: {}\nType: {}").format(uid, contact_type) + text=self._("Chat Recommendation Received\nID: {}\nType: {}").format(uid, contact_type), ) return [efb_msg] def qq_bface_wrapper(self, data, chat: Chat = None): efb_msg = Message( type=MsgType.Unsupported, - text=self._('[Here comes the BigFace Emoji, please check it on your phone]') + text=self._("[Here comes the BigFace Emoji, please check it on your phone]"), ) return [efb_msg] @@ -114,12 +113,11 @@ class QQMsgProcessor: pass def qq_sign_wrapper(self, data, chat: Chat = None): - location = self._('at {}').format(data['location']) if 'location' in data else self._('at Unknown Place') - title = '' if 'title' not in data else (self._('with title {}').format(data['title'])) + location = self._("at {}").format(data["location"]) if "location" in data else self._("at Unknown Place") + title = "" if "title" not in data else (self._("with title {}").format(data["title"])) efb_msg = Message( type=MsgType.Text, - text=self._('signed in {location} {title}').format(title=title, - location=location) + text=self._("signed in {location} {title}").format(title=title, location=location), ) return [efb_msg] @@ -127,10 +125,10 @@ class QQMsgProcessor: efb_messages = list() efb_msg = Message( type=MsgType.Unsupported, - text=self._('[Here comes the Rich Text, dumping...] \n') + text=self._("[Here comes the Rich Text, dumping...] \n"), ) for key, value in data.items(): - efb_msg.text += key + ': ' + value + '\n' + efb_msg.text += key + ": " + value + "\n" efb_messages.append(efb_msg) # Optimizations for rich messages # Group Broadcast @@ -142,12 +140,12 @@ class QQMsgProcessor: def qq_music_wrapper(self, data, chat: Chat = None): efb_msg = Message() - if data['type'] == '163': # Netease Cloud Music + if data["type"] == "163": # Netease Cloud Music efb_msg.type = MsgType.Text - efb_msg.text = 'https://music.163.com/#/song?id=' + data['id'] + efb_msg.text = "https://music.163.com/#/song?id=" + data["id"] else: efb_msg.type = MsgType.Text - efb_msg.text = data['text'] + efb_msg.text = data["text"] return [efb_msg] # todo Port for other music platform def qq_text_simple_wrapper(self, text: str, ats: dict): # This cute function only accepts string! @@ -160,7 +158,7 @@ class QQMsgProcessor: return efb_msg def coolq_code_at_wrapper(self, uid): - return '[CQ:at,qq={}]'.format(uid) + return "[CQ:at,qq={}]".format(uid) def coolq_code_image_wrapper(self, file, file_path): if file.closed: @@ -168,7 +166,7 @@ class QQMsgProcessor: encoded_string = base64.b64encode(file.read()) # Since base64 doesn't contain characters which isn't allowed in CQ Code, # there's no need to escape the special characters - return '[CQ:image,file=base64://{}]'.format(encoded_string.decode()) + return "[CQ:image,file=base64://{}]".format(encoded_string.decode()) def coolq_voice_image_wrapper(self, file, file_path): if file.closed: @@ -176,38 +174,39 @@ class QQMsgProcessor: encoded_string = base64.b64encode(file.read()) # Since base64 doesn't contain characters which isn't allowed in CQ Code, # there's no need to escape the special characters - return '[CQ:record,file=base64://{}]'.format(encoded_string.decode()) + return "[CQ:record,file=base64://{}]".format(encoded_string.decode()) def qq_file_after_wrapper(self, data): efb_msg = Message() - efb_msg.file = data['file'] + efb_msg.file = data["file"] efb_msg.type = MsgType.File mime = magic.from_file(efb_msg.file.name, mime=True) if isinstance(mime, bytes): mime = mime.decode() efb_msg.path = efb_msg.file.name efb_msg.mime = mime - efb_msg.filename = data['filename'] + efb_msg.filename = data["filename"] return efb_msg def qq_group_broadcast_wrapper(self, data, chat: Chat = None): try: at_list = {} - content_data = json.loads(data['content']) - text_data = base64.b64decode(content_data['mannounce']['text']).decode("UTF-8") - title_data = base64.b64decode(content_data['mannounce']['title']).decode("UTF-8") + content_data = json.loads(data["content"]) + text_data = base64.b64decode(content_data["mannounce"]["text"]).decode("UTF-8") + title_data = base64.b64decode(content_data["mannounce"]["title"]).decode("UTF-8") text = "[群公告] 【{title}】\n{text}".format(title=title_data, text=text_data) substitution_begin = len(text) + 1 - substitution_end = len(text) + len('@all') + 2 - text += ' @all ' + substitution_end = len(text) + len("@all") + 2 + text += " @all " at_list[(substitution_begin, substitution_end)] = chat.self - if 'pic' in content_data['mannounce']: # Picture Attached + if "pic" in content_data["mannounce"]: # Picture Attached # Assuming there's only one picture - data['url'] = "http://gdynamic.qpic.cn/gdynamic/{}/628".format( - content_data['mannounce']['pic'][0]['url']) + data["url"] = "http://gdynamic.qpic.cn/gdynamic/{}/628".format( + content_data["mannounce"]["pic"][0]["url"] + ) efb_message = self.qq_image_wrapper(data)[0] efb_message.text = text efb_message.substitutions = Substitutions(at_list) @@ -220,24 +219,23 @@ class QQMsgProcessor: def qq_group_broadcast_alternative_wrapper(self, data, chat: Chat = None): try: at_list = {} - content_data = json.loads(data['content']) - group_id = content_data['mannounce']['gc'] - notice_raw_data = self.inst.coolq_api_query("_get_group_notice", - group_id=group_id) + content_data = json.loads(data["content"]) + group_id = content_data["mannounce"]["gc"] + notice_raw_data = self.inst.coolq_api_query("_get_group_notice", group_id=group_id) notice_data = json.loads(notice_raw_data) - title_data = html.unescape(notice_data[0]['msg']['title']) - text_data = html.unescape(notice_data[0]['msg']['text']) + title_data = html.unescape(notice_data[0]["msg"]["title"]) + text_data = html.unescape(notice_data[0]["msg"]["text"]) text = "[群公告] 【{title}】\n{text}".format(title=title_data, text=text_data) substitution_begin = len(text) + 1 - substitution_end = len(text) + len('@all') + 2 - text += ' @all ' + substitution_end = len(text) + len("@all") + 2 + text += " @all " at_list[(substitution_begin, substitution_end)] = chat.self - if 'pics' in html.unescape(notice_data[0]['msg']): # Picture Attached + if "pics" in html.unescape(notice_data[0]["msg"]): # Picture Attached # Assuming there's only one picture - data['url'] = "http://gdynamic.qpic.cn/gdynamic/{}/628".format(notice_data[0]['msg']['pics'][0]['id']) + data["url"] = "http://gdynamic.qpic.cn/gdynamic/{}/628".format(notice_data[0]["msg"]["pics"][0]["id"]) efb_message = self.qq_image_wrapper(data)[0] efb_message.text = text efb_message.substitutions = Substitutions(at_list) @@ -250,66 +248,75 @@ class QQMsgProcessor: def qq_xml_wrapper(self, data, chat: Chat = None): efb_msg = Message() efb_msg.type = MsgType.Text - efb_msg.text = data['data'] + efb_msg.text = data["data"] return [efb_msg] def qq_json_wrapper(self, data, chat: Chat = None): efb_msg = Message() efb_msg.type = MsgType.Text - efb_msg.text = data['data'] + efb_msg.text = data["data"] try: # In general, data['data'] is a JSON string dict_data = json.loads(efb_msg.text) - if type(dict_data) != dict or 'app' not in dict_data: + if type(dict_data) != dict or "app" not in dict_data: return [efb_msg] # Group of announcement - if dict_data['app'] == 'com.tencent.mannounce': - meta_mannounce = dict_data['meta']['mannounce'] - efb_msg.text = "[{prompt}]\n\n{text}".format(prompt=str(base64.b64decode(meta_mannounce['title']), 'UTF-8'), text=str(base64.b64decode(meta_mannounce['text']), 'UTF-8')) + if dict_data["app"] == "com.tencent.mannounce": + meta_mannounce = dict_data["meta"]["mannounce"] + efb_msg.text = "[{prompt}]\n\n{text}".format( + prompt=str(base64.b64decode(meta_mannounce["title"]), "UTF-8"), + text=str(base64.b64decode(meta_mannounce["text"]), "UTF-8"), + ) # Watch, listen and play together - elif dict_data['app'] == 'com.tencent.together': - meta_invite = dict_data['meta']['invite'] - efb_msg.text = "[{prompt}]\n\n{text}\n\n{cover}".format(prompt=meta_invite['title'], text=meta_invite['summary'], cover=meta_invite['cover']) + elif dict_data["app"] == "com.tencent.together": + meta_invite = dict_data["meta"]["invite"] + efb_msg.text = "[{prompt}]\n\n{text}\n\n{cover}".format( + prompt=meta_invite["title"], + text=meta_invite["summary"], + cover=meta_invite["cover"], + ) # QQ vip card - elif dict_data['app'] == 'com.tencent.qqvip_singlepic': + elif dict_data["app"] == "com.tencent.qqvip_singlepic": efb_msg.text = efb_msg.text # Tencent mini App (01 unknown) - elif dict_data['app'] == 'com.tencent.miniapp_01': - meta_detail1 = dict_data['meta']['detail_1'] - url = meta_detail1['qqdocurl'] if 'qqdocurl' in meta_detail1 else meta_detail1['url'] - efb_msg.text = "{prompt}\n\n{desc}\n\n{url}\n\n{preview}".format(prompt=dict_data['prompt'], desc=meta_detail1['desc'], url=url, preview=meta_detail1['preview']) + elif dict_data["app"] == "com.tencent.miniapp_01": + meta_detail1 = dict_data["meta"]["detail_1"] + url = meta_detail1["qqdocurl"] if "qqdocurl" in meta_detail1 else meta_detail1["url"] + efb_msg.text = "{prompt}\n\n{desc}\n\n{url}\n\n{preview}".format( + prompt=dict_data["prompt"], + desc=meta_detail1["desc"], + url=url, + preview=meta_detail1["preview"], + ) # Shared third-party Apps - elif dict_data['app'] == 'com.tencent.structmsg': - meta_view = dict_data['meta'][dict_data['view']] - efb_msg.text = "{prompt}\n\n{desc}\n\n{url}\n\n{preview}".format(prompt=dict_data['prompt'], desc=meta_view['desc'], url=meta_view['jumpUrl'], preview=meta_view['preview']) + elif dict_data["app"] == "com.tencent.structmsg": + meta_view = dict_data["meta"][dict_data["view"]] + efb_msg.text = "{prompt}\n\n{desc}\n\n{url}\n\n{preview}".format( + prompt=dict_data["prompt"], + desc=meta_view["desc"], + url=meta_view["jumpUrl"], + preview=meta_view["preview"], + ) - except: + except Exception: self.logger.error(f"json_wrapper_info: {data}\nexc_info:{sys.exc_info()[0]}") return [efb_msg] def qq_video_wrapper(self, data, chat: Chat = None): - res = download_file(data['url']) + res = download_file(data["url"]) mime = magic.from_file(res.name, mime=True) if isinstance(mime, bytes): mime = mime.decode() - efb_msg = Message( - type=MsgType.Video, - file=res, - filename=res.name, - mime=mime - ) + efb_msg = Message(type=MsgType.Video, file=res, filename=res.name, mime=mime) return [efb_msg] def qq_unsupported_wrapper(self, data, chat: Chat = None): - efb_msg = Message( - type=MsgType.Unsupported, - text=data - ) + efb_msg = Message(type=MsgType.Unsupported, text=data) return [efb_msg] diff --git a/efb_qq_plugin_go_cqhttp/Utils.py b/efb_qq_plugin_go_cqhttp/Utils.py index 8655705..a7ef858 100644 --- a/efb_qq_plugin_go_cqhttp/Utils.py +++ b/efb_qq_plugin_go_cqhttp/Utils.py @@ -2,643 +2,646 @@ import logging import tempfile import urllib.request from gettext import translation -from urllib.error import URLError, HTTPError, ContentTooShortError +from urllib.error import ContentTooShortError, HTTPError, URLError from ehforwarderbot import Message, coordinator from pkg_resources import resource_filename -qq_emoji_list = { # created by JogleLew and jqqqqqqqqqq, optimized based on Tim's emoji support, updated by xzsk2 to mobileqq v8.8.11 - 0: '😮', - 1: '😣', - 2: '😍', - 3: '😳', - 4: '😎', - 5: '😭', - 6: '☺️', - 7: '😷', - 8: '😴', - 9: '😭', - 10: '😰', - 11: '😡', - 12: '😝', - 13: '😃', - 14: '🙂', - 15: '🙁', - 16: '🤓', - 17: '[Empty]', - 18: '😤', - 19: '😨', - 20: '😏', - 21: '😊', - 22: '🙄', - 23: '😕', - 24: '🤤', - 25: '😪', - 26: '😨', - 27: '😓', - 28: '😬', - 29: '🤑', - 30: '✊', - 31: '😤', - 32: '🤔', - 33: '🤐', - 34: '😵', - 35: '😩', - 36: '💣', - 37: '💀', - 38: '🔨', - 39: '👋', - 40: '[Empty]', - 41: '😮', - 42: '💑', - 43: '🕺', - 44: '[Empty]', - 45: '[Empty]', - 46: '🐷', - 47: '[Empty]', - 48: '[Empty]', - 49: '🤷', - 50: '[Empty]', - 51: '[Empty]', - 52: '[Empty]', - 53: '🎂', - 54: '⚡', - 55: '💣', - 56: '🔪', - 57: '⚽️', - 58: '[Empty]', - 59: '💩', - 60: '☕️', - 61: '🍚', - 62: '[Empty]', - 63: '🌹', - 64: '🥀', - 65: '[Empty]', - 66: '❤️', - 67: '💔️', - 68: '[Empty]', - 69: '🎁', - 70: '[Empty]', - 71: '[Empty]', - 72: '[Empty]', - 73: '[Empty]', - 74: '🌞️', - 75: '🌃', - 76: '👍', - 77: '👎', - 78: '🤝', - 79: '✌️', - 80: '[Empty]', - 81: '[Empty]', - 82: '[Empty]', - 83: '[Empty]', - 84: '[Empty]', - 85: '🥰', - 86: '[怄火]', - 87: '[Empty]', - 88: '[Empty]', - 89: '🍉', - 90: '[Empty]', - 91: '[Empty]', - 92: '[Empty]', - 93: '[Empty]', - 94: '[Empty]', - 95: '[Empty]', - 96: '😅', - 97: '[擦汗]', - 98: '[抠鼻]', - 99: '👏', - 100: '[糗大了]', - 101: '😏', - 102: '😏', - 103: '😏', - 104: '🥱', - 105: '[鄙视]', - 106: '😭', - 107: '😭', - 108: '[阴险]', - 109: '😚', - 110: '🙀', - 111: '[可怜]', - 112: '🔪', - 113: '🍺', - 114: '🏀', - 115: '🏓', - 116: '❤️', - 117: '🐞', - 118: '[抱拳]', - 119: '[勾引]', - 120: '✊', - 121: '[差劲]', - 122: '🤟', - 123: '🚫', - 124: '👌', - 125: '[转圈]', - 126: '[磕头]', - 127: '[回头]', - 128: '[跳绳]', - 129: '👋', - 130: '[激动]', - 131: '[街舞]', - 132: '😘', - 133: '[左太极]', - 134: '[右太极]', - 135: '[Empty]', - 136: '[双喜]', - 137: '🧨', - 138: '🏮', - 139: '💰', - 140: '[K歌]', - 141: '🛍️', - 142: '📧', - 143: '[帅]', - 144: '👏', - 145: '🙏', - 146: '[爆筋]', - 147: '🍭', - 148: '🍼', - 149: '[下面]', - 150: '🍌', - 151: '🛩', - 152: '🚗', - 153: '🚅', - 154: '[车厢]', - 155: '[高铁右车头]', - 156: '🌥', - 157: '下雨', - 158: '💵', - 159: '🐼', - 160: '💡', - 161: '[风车]', - 162: '⏰', - 163: '🌂', - 164: '[彩球]', - 165: '💍', - 166: '🛋', - 167: '[纸巾]', - 168: '💊', - 169: '🔫', - 170: '🐸', - 171: '🍵', - 172: '[眨眼睛]', - 173: '😭', - 174: '[无奈]', - 175: '[卖萌]', - 176: '[小纠结]', - 177: '[喷血]', - 178: '[斜眼笑]', - 179: '[doge]', - 180: '[惊喜]', - 181: '[骚扰]', - 182: '😹', - 183: '[我最美]', - 184: '🦀', - 185: '[羊驼]', - 186: '[Empty]', - 187: '👻', - 188: '🥚', - 189: '[Empty]', - 190: '🌼', - 191: '[Empty]', - 192: '🧧', - 193: '😄', - 194: '😞', - 195: '[Empty]', - 196: '[Empty]', - 197: '[冷漠]', - 198: '[呃]', - 199: '👍', - 200: '👋', - 201: '👍', - 202: '[无聊]', - 203: '[托脸]', - 204: '[吃]', - 205: '💐', - 206: '😨', - 207: '[花痴]', - 208: '[小样儿]', - 209: '[Empty]', - 210: '😭', - 211: '[我不看]', - 212: '[托腮]', - 213: '[Empty]', - 214: '😙', - 215: '[糊脸]', - 216: '[拍头]', - 217: '[扯一扯]', - 218: '[舔一舔]', - 219: '[蹭一蹭]', - 220: '[拽炸天]', - 221: '[顶呱呱]', - 222: '🤗', - 223: '[暴击]', - 224: '🔫', - 225: '[撩一撩]', - 226: '[拍桌]', - 227: '👏', - 228: '[恭喜]', - 229: '🍻', - 230: '[嘲讽]', - 231: '[哼]', - 232: '[佛系]', - 233: '[掐一掐]', - 234: '😮', - 235: '[颤抖]', - 236: '[啃头]', - 237: '[偷看]', - 238: '[扇脸]', - 239: '[原谅]', - 240: '[喷脸]', - 241: '🎂', - 242: '[头撞击]', - 243: '[甩头]', - 244: '[扔狗]', - 245: '[加油必胜]', - 246: '[加油抱抱]', - 247: '[口罩护体]', - 248: '[Empty]', - 249: '[Empty]', - 250: '[Empty]', - 251: '[Empty]', - 252: '[Empty]', - 253: '[Empty]', - 254: '[Empty]', - 255: '[Empty]', - 256: '😲', - 257: '😟', - 258: '😍', - 259: '😳', - 260: '[搬砖中]', - 261: '[忙到飞起]', - 262: '[脑阔疼]', - 263: '[沧桑]', - 264: '[捂脸]', - 265: '[辣眼睛]', - 266: '[哦哟]', - 267: '[头秃]', - 268: '[问号脸]', - 269: '[暗中观察]', - 270: '[emm]', - 271: '[吃瓜]', - 272: '[呵呵哒]', - 273: '[我酸了]', - 274: '[太南了]', - 275: '[Empty]', - 276: '[辣椒酱]', - 277: '[汪汪]', - 278: '[汗]', - 279: '[打脸]', - 280: '[击掌]', - 281: '[无眼笑]', - 282: '[敬礼]', - 283: '[狂笑]', - 284: '[面无表情]', - 285: '[摸鱼]', - 286: '[魔鬼笑]', - 287: '[哦]', - 288: '[请]', - 289: '[睁眼]', - 290: '[敲开心]', - 291: '[震惊]', - 292: '[让我康康]', - 293: '[摸锦鲤]', - 294: '[期待]', - 295: '[拿到红包]', - 296: '[真好]', - 297: '[拜谢]', - 298: '[元宝]', - 299: '[牛啊]', - 300: '[胖三斤]', - 301: '[好闪]', - 302: '[左拜年]', - 303: '[右拜年]', - 304: '[红包包]', - 305: '[右亲亲]', - 306: '[牛气冲天]', - 307: '[喵喵]', - 308: '[求红包]', - 309: '[谢红包]', - 310: '[新年烟花]', - 311: '[打call]', - 312: '[变形]', - 313: '[嗑到了]', - 314: '[仔细分析]', - 315: '[加油]', - 316: '[我没事]', - 317: '[菜狗]', - 318: '[崇拜]', - 319: '[比心]', - 320: '[庆祝]', - 321: '[老色痞]', - 322: '[拒绝]', - 323: '[嫌弃]', +# created by JogleLew and jqqqqqqqqqq, optimized based on Tim's emoji support, updated by xzsk2 to mobileqq v8.8.11 +qq_emoji_list = { + 0: "😮", + 1: "😣", + 2: "😍", + 3: "😳", + 4: "😎", + 5: "😭", + 6: "☺️", + 7: "😷", + 8: "😴", + 9: "😭", + 10: "😰", + 11: "😡", + 12: "😝", + 13: "😃", + 14: "🙂", + 15: "🙁", + 16: "🤓", + 17: "[Empty]", + 18: "😤", + 19: "😨", + 20: "😏", + 21: "😊", + 22: "🙄", + 23: "😕", + 24: "🤤", + 25: "😪", + 26: "😨", + 27: "😓", + 28: "😬", + 29: "🤑", + 30: "✊", + 31: "😤", + 32: "🤔", + 33: "🤐", + 34: "😵", + 35: "😩", + 36: "💣", + 37: "💀", + 38: "🔨", + 39: "👋", + 40: "[Empty]", + 41: "😮", + 42: "💑", + 43: "🕺", + 44: "[Empty]", + 45: "[Empty]", + 46: "🐷", + 47: "[Empty]", + 48: "[Empty]", + 49: "🤷", + 50: "[Empty]", + 51: "[Empty]", + 52: "[Empty]", + 53: "🎂", + 54: "⚡", + 55: "💣", + 56: "🔪", + 57: "⚽️", + 58: "[Empty]", + 59: "💩", + 60: "☕️", + 61: "🍚", + 62: "[Empty]", + 63: "🌹", + 64: "🥀", + 65: "[Empty]", + 66: "❤️", + 67: "💔️", + 68: "[Empty]", + 69: "🎁", + 70: "[Empty]", + 71: "[Empty]", + 72: "[Empty]", + 73: "[Empty]", + 74: "🌞️", + 75: "🌃", + 76: "👍", + 77: "👎", + 78: "🤝", + 79: "✌️", + 80: "[Empty]", + 81: "[Empty]", + 82: "[Empty]", + 83: "[Empty]", + 84: "[Empty]", + 85: "🥰", + 86: "[怄火]", + 87: "[Empty]", + 88: "[Empty]", + 89: "🍉", + 90: "[Empty]", + 91: "[Empty]", + 92: "[Empty]", + 93: "[Empty]", + 94: "[Empty]", + 95: "[Empty]", + 96: "😅", + 97: "[擦汗]", + 98: "[抠鼻]", + 99: "👏", + 100: "[糗大了]", + 101: "😏", + 102: "😏", + 103: "😏", + 104: "🥱", + 105: "[鄙视]", + 106: "😭", + 107: "😭", + 108: "[阴险]", + 109: "😚", + 110: "🙀", + 111: "[可怜]", + 112: "🔪", + 113: "🍺", + 114: "🏀", + 115: "🏓", + 116: "❤️", + 117: "🐞", + 118: "[抱拳]", + 119: "[勾引]", + 120: "✊", + 121: "[差劲]", + 122: "🤟", + 123: "🚫", + 124: "👌", + 125: "[转圈]", + 126: "[磕头]", + 127: "[回头]", + 128: "[跳绳]", + 129: "👋", + 130: "[激动]", + 131: "[街舞]", + 132: "😘", + 133: "[左太极]", + 134: "[右太极]", + 135: "[Empty]", + 136: "[双喜]", + 137: "🧨", + 138: "🏮", + 139: "💰", + 140: "[K歌]", + 141: "🛍️", + 142: "📧", + 143: "[帅]", + 144: "👏", + 145: "🙏", + 146: "[爆筋]", + 147: "🍭", + 148: "🍼", + 149: "[下面]", + 150: "🍌", + 151: "🛩", + 152: "🚗", + 153: "🚅", + 154: "[车厢]", + 155: "[高铁右车头]", + 156: "🌥", + 157: "下雨", + 158: "💵", + 159: "🐼", + 160: "💡", + 161: "[风车]", + 162: "⏰", + 163: "🌂", + 164: "[彩球]", + 165: "💍", + 166: "🛋", + 167: "[纸巾]", + 168: "💊", + 169: "🔫", + 170: "🐸", + 171: "🍵", + 172: "[眨眼睛]", + 173: "😭", + 174: "[无奈]", + 175: "[卖萌]", + 176: "[小纠结]", + 177: "[喷血]", + 178: "[斜眼笑]", + 179: "[doge]", + 180: "[惊喜]", + 181: "[骚扰]", + 182: "😹", + 183: "[我最美]", + 184: "🦀", + 185: "[羊驼]", + 186: "[Empty]", + 187: "👻", + 188: "🥚", + 189: "[Empty]", + 190: "🌼", + 191: "[Empty]", + 192: "🧧", + 193: "😄", + 194: "😞", + 195: "[Empty]", + 196: "[Empty]", + 197: "[冷漠]", + 198: "[呃]", + 199: "👍", + 200: "👋", + 201: "👍", + 202: "[无聊]", + 203: "[托脸]", + 204: "[吃]", + 205: "💐", + 206: "😨", + 207: "[花痴]", + 208: "[小样儿]", + 209: "[Empty]", + 210: "😭", + 211: "[我不看]", + 212: "[托腮]", + 213: "[Empty]", + 214: "😙", + 215: "[糊脸]", + 216: "[拍头]", + 217: "[扯一扯]", + 218: "[舔一舔]", + 219: "[蹭一蹭]", + 220: "[拽炸天]", + 221: "[顶呱呱]", + 222: "🤗", + 223: "[暴击]", + 224: "🔫", + 225: "[撩一撩]", + 226: "[拍桌]", + 227: "👏", + 228: "[恭喜]", + 229: "🍻", + 230: "[嘲讽]", + 231: "[哼]", + 232: "[佛系]", + 233: "[掐一掐]", + 234: "😮", + 235: "[颤抖]", + 236: "[啃头]", + 237: "[偷看]", + 238: "[扇脸]", + 239: "[原谅]", + 240: "[喷脸]", + 241: "🎂", + 242: "[头撞击]", + 243: "[甩头]", + 244: "[扔狗]", + 245: "[加油必胜]", + 246: "[加油抱抱]", + 247: "[口罩护体]", + 248: "[Empty]", + 249: "[Empty]", + 250: "[Empty]", + 251: "[Empty]", + 252: "[Empty]", + 253: "[Empty]", + 254: "[Empty]", + 255: "[Empty]", + 256: "😲", + 257: "😟", + 258: "😍", + 259: "😳", + 260: "[搬砖中]", + 261: "[忙到飞起]", + 262: "[脑阔疼]", + 263: "[沧桑]", + 264: "[捂脸]", + 265: "[辣眼睛]", + 266: "[哦哟]", + 267: "[头秃]", + 268: "[问号脸]", + 269: "[暗中观察]", + 270: "[emm]", + 271: "[吃瓜]", + 272: "[呵呵哒]", + 273: "[我酸了]", + 274: "[太南了]", + 275: "[Empty]", + 276: "[辣椒酱]", + 277: "[汪汪]", + 278: "[汗]", + 279: "[打脸]", + 280: "[击掌]", + 281: "[无眼笑]", + 282: "[敬礼]", + 283: "[狂笑]", + 284: "[面无表情]", + 285: "[摸鱼]", + 286: "[魔鬼笑]", + 287: "[哦]", + 288: "[请]", + 289: "[睁眼]", + 290: "[敲开心]", + 291: "[震惊]", + 292: "[让我康康]", + 293: "[摸锦鲤]", + 294: "[期待]", + 295: "[拿到红包]", + 296: "[真好]", + 297: "[拜谢]", + 298: "[元宝]", + 299: "[牛啊]", + 300: "[胖三斤]", + 301: "[好闪]", + 302: "[左拜年]", + 303: "[右拜年]", + 304: "[红包包]", + 305: "[右亲亲]", + 306: "[牛气冲天]", + 307: "[喵喵]", + 308: "[求红包]", + 309: "[谢红包]", + 310: "[新年烟花]", + 311: "[打call]", + 312: "[变形]", + 313: "[嗑到了]", + 314: "[仔细分析]", + 315: "[加油]", + 316: "[我没事]", + 317: "[菜狗]", + 318: "[崇拜]", + 319: "[比心]", + 320: "[庆祝]", + 321: "[老色痞]", + 322: "[拒绝]", + 323: "[嫌弃]", } # original text copied from Tim qq_emoji_text_list = { - 0: '[惊讶]', - 1: '[撇嘴]', - 2: '[色]', - 3: '[发呆]', - 4: '[得意]', - 5: '[流泪]', - 6: '[害羞]', - 7: '[闭嘴]', - 8: '[睡]', - 9: '[大哭]', - 10: '[尴尬]', - 11: '[发怒]', - 12: '[调皮]', - 13: '[呲牙]', - 14: '[微笑]', - 15: '[难过]', - 16: '[酷]', - 17: '[Empty]', - 18: '[抓狂]', - 19: '[吐]', - 20: '[偷笑]', - 21: '[可爱]', - 22: '[白眼]', - 23: '[傲慢]', - 24: '[饥饿]', - 25: '[困]', - 26: '[惊恐]', - 27: '[流汗]', - 28: '[憨笑]', - 29: '[悠闲]', - 30: '[奋斗]', - 31: '[咒骂]', - 32: '[疑问]', - 33: '[嘘]', - 34: '[晕]', - 35: '[折磨]', - 36: '[衰]', - 37: '[骷髅]', - 38: '[敲打]', - 39: '[再见]', - 40: '[Empty]', - 41: '[发抖]', - 42: '[爱情]', - 43: '[跳跳]', - 44: '[Empty]', - 45: '[Empty]', - 46: '[猪头]', - 47: '[Empty]', - 48: '[Empty]', - 49: '[拥抱]', - 50: '[Empty]', - 51: '[Empty]', - 52: '[Empty]', - 53: '[蛋糕]', - 54: '[闪电]', - 55: '[炸弹]', - 56: '[刀]', - 57: '[足球]', - 58: '[Empty]', - 59: '[便便]', - 60: '[咖啡]', - 61: '[饭]', - 62: '[Empty]', - 63: '[玫瑰]', - 64: '[凋谢]', - 65: '[Empty]', - 66: '[爱心]', - 67: '[心碎]', - 68: '[Empty]', - 69: '[礼物]', - 70: '[Empty]', - 71: '[Empty]', - 72: '[Empty]', - 73: '[Empty]', - 74: '[太阳]', - 75: '[月亮]', - 76: '[赞]', - 77: '[踩]', - 78: '[握手]', - 79: '[胜利]', - 80: '[Empty]', - 81: '[Empty]', - 82: '[Empty]', - 83: '[Empty]', - 84: '[Empty]', - 85: '[飞吻]', - 86: '[怄火]', - 87: '[Empty]', - 88: '[Empty]', - 89: '[西瓜]', - 90: '[Empty]', - 91: '[Empty]', - 92: '[Empty]', - 93: '[Empty]', - 94: '[Empty]', - 95: '[Empty]', - 96: '[冷汗]', - 97: '[擦汗]', - 98: '[抠鼻]', - 99: '[鼓掌]', - 100: '[糗大了]', - 101: '[坏笑]', - 102: '[左哼哼]', - 103: '[右哼哼]', - 104: '[哈欠]', - 105: '[鄙视]', - 106: '[委屈]', - 107: '[快哭了]', - 108: '[阴险]', - 109: '[亲亲]', - 110: '[吓]', - 111: '[可怜]', - 112: '[菜刀]', - 113: '[啤酒]', - 114: '[篮球]', - 115: '[乒乓]', - 116: '[示爱]', - 117: '[瓢虫]', - 118: '[抱拳]', - 119: '[勾引]', - 120: '[拳头]', - 121: '[差劲]', - 122: '[爱你]', - 123: '[NO]', - 124: '[OK]', - 125: '[转圈]', - 126: '[磕头]', - 127: '[回头]', - 128: '[跳绳]', - 129: '[挥手]', - 130: '[激动]', - 131: '[街舞]', - 132: '[献吻]', - 133: '[左太极]', - 134: '[右太极]', - 135: '[Empty]', - 136: '[双喜]', - 137: '[鞭炮]', - 138: '[灯笼]', - 139: '[发财]', - 140: '[K歌]', - 141: '[购物]', - 142: '[邮件]', - 143: '[帅]', - 144: '[喝彩]', - 145: '[祈祷]', - 146: '[爆筋]', - 147: '[棒棒糖]', - 148: '[喝奶]', - 149: '[下面]', - 150: '[香蕉]', - 151: '[飞机]', - 152: '[开车]', - 153: '[高铁左车头]', - 154: '[车厢]', - 155: '[高铁右车头]', - 156: '[多云]', - 157: '[下雨]', - 158: '[钞票]', - 159: '[熊猫]', - 160: '[灯泡]', - 161: '[风车]', - 162: '[闹钟]', - 163: '[打伞]', - 164: '[彩球]', - 165: '[钻戒]', - 166: '[沙发]', - 167: '[纸巾]', - 168: '[药]', - 169: '[手枪]', - 170: '[青蛙]', - 171: '[茶]', - 172: '[眨眼睛]', - 173: '[泪奔]', - 174: '[无奈]', - 175: '[卖萌]', - 176: '[小纠结]', - 177: '[喷血]', - 178: '[斜眼笑]', - 179: '[doge]', - 180: '[惊喜]', - 181: '[骚扰]', - 182: '[笑哭]', - 183: '[我最美]', - 184: '[河蟹]', - 185: '[羊驼]', - 186: '[Empty]', - 187: '[幽灵]', - 188: '[蛋]', - 189: '[Empty]', - 190: '[菊花]', - 191: '[Empty]', - 192: '[红包]', - 193: '[大笑]', - 194: '[不开心]', - 195: '[Empty]', - 196: '[Empty]', - 197: '[冷漠]', - 198: '[呃]', - 199: '[好棒]', - 200: '[拜托]', - 201: '[点赞]', - 202: '[无聊]', - 203: '[托脸]', - 204: '[吃]', - 205: '[送花]', - 206: '[害怕]', - 207: '[花痴]', - 208: '[小样儿]', - 209: '[Empty]', - 210: '[飙泪]', - 211: '[我不看]', - 212: '[托腮]', - 213: '[Empty]', - 214: '[啵啵]', - 215: '[糊脸]', - 216: '[拍头]', - 217: '[扯一扯]', - 218: '[舔一舔]', - 219: '[蹭一蹭]', - 220: '[拽炸天]', - 221: '[顶呱呱]', - 222: '[抱抱]', - 223: '[暴击]', - 224: '[开枪]', - 225: '[撩一撩]', - 226: '[拍桌]', - 227: '[拍手]', - 228: '[恭喜]', - 229: '[干杯]', - 230: '[嘲讽]', - 231: '[哼]', - 232: '[佛系]', - 233: '[掐一掐]', - 234: '[惊呆]', - 235: '[颤抖]', - 236: '[啃头]', - 237: '[偷看]', - 238: '[扇脸]', - 239: '[原谅]', - 240: '[喷脸]', - 241: '[生日快乐]', - 242: '[Empty]', - 243: '[Empty]', - 244: '[Empty]', - 245: '[Empty]', - 246: '[Empty]', - 247: '[Empty]', - 248: '[Empty]', - 249: '[Empty]', - 250: '[Empty]', - 251: '[Empty]', - 252: '[Empty]', - 253: '[Empty]', - 254: '[Empty]', - 255: '[Empty]', + 0: "[惊讶]", + 1: "[撇嘴]", + 2: "[色]", + 3: "[发呆]", + 4: "[得意]", + 5: "[流泪]", + 6: "[害羞]", + 7: "[闭嘴]", + 8: "[睡]", + 9: "[大哭]", + 10: "[尴尬]", + 11: "[发怒]", + 12: "[调皮]", + 13: "[呲牙]", + 14: "[微笑]", + 15: "[难过]", + 16: "[酷]", + 17: "[Empty]", + 18: "[抓狂]", + 19: "[吐]", + 20: "[偷笑]", + 21: "[可爱]", + 22: "[白眼]", + 23: "[傲慢]", + 24: "[饥饿]", + 25: "[困]", + 26: "[惊恐]", + 27: "[流汗]", + 28: "[憨笑]", + 29: "[悠闲]", + 30: "[奋斗]", + 31: "[咒骂]", + 32: "[疑问]", + 33: "[嘘]", + 34: "[晕]", + 35: "[折磨]", + 36: "[衰]", + 37: "[骷髅]", + 38: "[敲打]", + 39: "[再见]", + 40: "[Empty]", + 41: "[发抖]", + 42: "[爱情]", + 43: "[跳跳]", + 44: "[Empty]", + 45: "[Empty]", + 46: "[猪头]", + 47: "[Empty]", + 48: "[Empty]", + 49: "[拥抱]", + 50: "[Empty]", + 51: "[Empty]", + 52: "[Empty]", + 53: "[蛋糕]", + 54: "[闪电]", + 55: "[炸弹]", + 56: "[刀]", + 57: "[足球]", + 58: "[Empty]", + 59: "[便便]", + 60: "[咖啡]", + 61: "[饭]", + 62: "[Empty]", + 63: "[玫瑰]", + 64: "[凋谢]", + 65: "[Empty]", + 66: "[爱心]", + 67: "[心碎]", + 68: "[Empty]", + 69: "[礼物]", + 70: "[Empty]", + 71: "[Empty]", + 72: "[Empty]", + 73: "[Empty]", + 74: "[太阳]", + 75: "[月亮]", + 76: "[赞]", + 77: "[踩]", + 78: "[握手]", + 79: "[胜利]", + 80: "[Empty]", + 81: "[Empty]", + 82: "[Empty]", + 83: "[Empty]", + 84: "[Empty]", + 85: "[飞吻]", + 86: "[怄火]", + 87: "[Empty]", + 88: "[Empty]", + 89: "[西瓜]", + 90: "[Empty]", + 91: "[Empty]", + 92: "[Empty]", + 93: "[Empty]", + 94: "[Empty]", + 95: "[Empty]", + 96: "[冷汗]", + 97: "[擦汗]", + 98: "[抠鼻]", + 99: "[鼓掌]", + 100: "[糗大了]", + 101: "[坏笑]", + 102: "[左哼哼]", + 103: "[右哼哼]", + 104: "[哈欠]", + 105: "[鄙视]", + 106: "[委屈]", + 107: "[快哭了]", + 108: "[阴险]", + 109: "[亲亲]", + 110: "[吓]", + 111: "[可怜]", + 112: "[菜刀]", + 113: "[啤酒]", + 114: "[篮球]", + 115: "[乒乓]", + 116: "[示爱]", + 117: "[瓢虫]", + 118: "[抱拳]", + 119: "[勾引]", + 120: "[拳头]", + 121: "[差劲]", + 122: "[爱你]", + 123: "[NO]", + 124: "[OK]", + 125: "[转圈]", + 126: "[磕头]", + 127: "[回头]", + 128: "[跳绳]", + 129: "[挥手]", + 130: "[激动]", + 131: "[街舞]", + 132: "[献吻]", + 133: "[左太极]", + 134: "[右太极]", + 135: "[Empty]", + 136: "[双喜]", + 137: "[鞭炮]", + 138: "[灯笼]", + 139: "[发财]", + 140: "[K歌]", + 141: "[购物]", + 142: "[邮件]", + 143: "[帅]", + 144: "[喝彩]", + 145: "[祈祷]", + 146: "[爆筋]", + 147: "[棒棒糖]", + 148: "[喝奶]", + 149: "[下面]", + 150: "[香蕉]", + 151: "[飞机]", + 152: "[开车]", + 153: "[高铁左车头]", + 154: "[车厢]", + 155: "[高铁右车头]", + 156: "[多云]", + 157: "[下雨]", + 158: "[钞票]", + 159: "[熊猫]", + 160: "[灯泡]", + 161: "[风车]", + 162: "[闹钟]", + 163: "[打伞]", + 164: "[彩球]", + 165: "[钻戒]", + 166: "[沙发]", + 167: "[纸巾]", + 168: "[药]", + 169: "[手枪]", + 170: "[青蛙]", + 171: "[茶]", + 172: "[眨眼睛]", + 173: "[泪奔]", + 174: "[无奈]", + 175: "[卖萌]", + 176: "[小纠结]", + 177: "[喷血]", + 178: "[斜眼笑]", + 179: "[doge]", + 180: "[惊喜]", + 181: "[骚扰]", + 182: "[笑哭]", + 183: "[我最美]", + 184: "[河蟹]", + 185: "[羊驼]", + 186: "[Empty]", + 187: "[幽灵]", + 188: "[蛋]", + 189: "[Empty]", + 190: "[菊花]", + 191: "[Empty]", + 192: "[红包]", + 193: "[大笑]", + 194: "[不开心]", + 195: "[Empty]", + 196: "[Empty]", + 197: "[冷漠]", + 198: "[呃]", + 199: "[好棒]", + 200: "[拜托]", + 201: "[点赞]", + 202: "[无聊]", + 203: "[托脸]", + 204: "[吃]", + 205: "[送花]", + 206: "[害怕]", + 207: "[花痴]", + 208: "[小样儿]", + 209: "[Empty]", + 210: "[飙泪]", + 211: "[我不看]", + 212: "[托腮]", + 213: "[Empty]", + 214: "[啵啵]", + 215: "[糊脸]", + 216: "[拍头]", + 217: "[扯一扯]", + 218: "[舔一舔]", + 219: "[蹭一蹭]", + 220: "[拽炸天]", + 221: "[顶呱呱]", + 222: "[抱抱]", + 223: "[暴击]", + 224: "[开枪]", + 225: "[撩一撩]", + 226: "[拍桌]", + 227: "[拍手]", + 228: "[恭喜]", + 229: "[干杯]", + 230: "[嘲讽]", + 231: "[哼]", + 232: "[佛系]", + 233: "[掐一掐]", + 234: "[惊呆]", + 235: "[颤抖]", + 236: "[啃头]", + 237: "[偷看]", + 238: "[扇脸]", + 239: "[原谅]", + 240: "[喷脸]", + 241: "[生日快乐]", + 242: "[Empty]", + 243: "[Empty]", + 244: "[Empty]", + 245: "[Empty]", + 246: "[Empty]", + 247: "[Empty]", + 248: "[Empty]", + 249: "[Empty]", + 250: "[Empty]", + 251: "[Empty]", + 252: "[Empty]", + 253: "[Empty]", + 254: "[Empty]", + 255: "[Empty]", } qq_sface_list = { - 1: '[拜拜]', - 2: '[鄙视]', - 3: '[菜刀]', - 4: '[沧桑]', - 5: '[馋了]', - 6: '[吃惊]', - 7: '[微笑]', - 8: '[得意]', - 9: '[嘚瑟]', - 10: '[瞪眼]', - 11: '[震惊]', - 12: '[鼓掌]', - 13: '[害羞]', - 14: '[好的]', - 15: '[惊呆了]', - 16: '[静静看]', - 17: '[可爱]', - 18: '[困]', - 19: '[脸红]', - 20: '[你懂的]', - 21: '[期待]', - 22: '[亲亲]', - 23: '[伤心]', - 24: '[生气]', - 25: '[摇摆]', - 26: '[帅]', - 27: '[思考]', - 28: '[震惊哭]', - 29: '[痛心]', - 30: '[偷笑]', - 31: '[挖鼻孔]', - 32: '[抓狂]', - 33: '[笑着哭]', - 34: '[无语]', - 35: '[捂脸]', - 36: '[喜欢]', - 37: '[笑哭]', - 38: '[疑惑]', - 39: '[赞]', - 40: '[眨眼]' + 1: "[拜拜]", + 2: "[鄙视]", + 3: "[菜刀]", + 4: "[沧桑]", + 5: "[馋了]", + 6: "[吃惊]", + 7: "[微笑]", + 8: "[得意]", + 9: "[嘚瑟]", + 10: "[瞪眼]", + 11: "[震惊]", + 12: "[鼓掌]", + 13: "[害羞]", + 14: "[好的]", + 15: "[惊呆了]", + 16: "[静静看]", + 17: "[可爱]", + 18: "[困]", + 19: "[脸红]", + 20: "[你懂的]", + 21: "[期待]", + 22: "[亲亲]", + 23: "[伤心]", + 24: "[生气]", + 25: "[摇摆]", + 26: "[帅]", + 27: "[思考]", + 28: "[震惊哭]", + 29: "[痛心]", + 30: "[偷笑]", + 31: "[挖鼻孔]", + 32: "[抓狂]", + 33: "[笑着哭]", + 34: "[无语]", + 35: "[捂脸]", + 36: "[喜欢]", + 37: "[笑哭]", + 38: "[疑惑]", + 39: "[赞]", + 40: "[眨眼]", } -translator = translation("efb_qq_slave", - resource_filename('efb_qq_slave', 'Clients/CoolQ/locale'), - fallback=True) +translator = translation( + "efb_qq_slave", + resource_filename("efb_qq_slave", "Clients/CoolQ/locale"), + fallback=True, +) _ = translator.gettext ngettext = translator.ngettext @@ -648,12 +651,12 @@ def cq_get_image(image_link: str) -> tempfile: # Download image from QQ try: urllib.request.urlretrieve(image_link, file.name) except (URLError, HTTPError, ContentTooShortError) as e: - logging.getLogger(__name__).warning('Image download failed.') + logging.getLogger(__name__).warning("Image download failed.") logging.getLogger(__name__).warning(str(e)) return None else: if file.seek(0, 2) <= 0: - raise EOFError('File downloaded is Empty') + raise EOFError("File downloaded is Empty") file.seek(0) return file @@ -679,14 +682,14 @@ def process_quote_text(text, max_length): # Simple wrapper for processing quote def coolq_text_encode(text: str): # Escape special characters for CQ Code text - expr = (('&', '&'), ('[', '['), (']', ']')) + expr = (("&", "&"), ("[", "["), ("]", "]")) for r in expr: text = text.replace(*r) return text def coolq_para_encode(text: str): # Escape special characters for CQ Code parameters - expr = (('&', '&'), ('[', '['), (']', ']'), (',', ',')) + expr = (("&", "&"), ("[", "["), ("]", "]"), (",", ",")) for r in expr: text = text.replace(*r) return text @@ -712,7 +715,7 @@ def download_file(download_url): return _("Error occurs when downloading files: ") + str(e) else: if file.seek(0, 2) <= 0: - raise EOFError('File downloaded is Empty') + raise EOFError("File downloaded is Empty") file.seek(0) return file @@ -728,7 +731,7 @@ def download_user_avatar(uid: str): logging.getLogger(__name__).warning("Error occurs when downloading files: " + str(e)) return _("Error occurs when downloading files: ") + str(e) if file.seek(0, 2) <= 0: - raise EOFError('File downloaded is Empty') + raise EOFError("File downloaded is Empty") file.seek(0) return file @@ -744,14 +747,14 @@ def download_group_avatar(uid: str): logging.getLogger(__name__).warning("Error occurs when downloading files: " + str(e)) return _("Error occurs when downloading files: ") + str(e) if file.seek(0, 2) <= 0: - raise EOFError('File downloaded is Empty') + raise EOFError("File downloaded is Empty") file.seek(0) return file def download_voice(filename: str, api_root: str, access_token: str): file = tempfile.NamedTemporaryFile() - url = '{url}/data/record/{file}'.format(url=api_root, file=filename) + url = "{url}/data/record/{file}".format(url=api_root, file=filename) try: opener = urllib.request.build_opener() opener.addheaders = [("Authorization", "Bearer {at}".format(at=access_token))] @@ -762,6 +765,6 @@ def download_voice(filename: str, api_root: str, access_token: str): logging.getLogger(__name__).warning("Error occurs when downloading files: " + str(e)) return _("Error occurs when downloading files: ") + str(e) if file.seek(0, 2) <= 0: - raise EOFError('File downloaded is Empty') + raise EOFError("File downloaded is Empty") file.seek(0) return file diff --git a/efb_qq_plugin_go_cqhttp/__init__.py b/efb_qq_plugin_go_cqhttp/__init__.py index 31009fb..7500abb 100644 --- a/efb_qq_plugin_go_cqhttp/__init__.py +++ b/efb_qq_plugin_go_cqhttp/__init__.py @@ -1,3 +1,3 @@ -from . import GoCQHttp +from . import GoCQHttp # noqa: F401 -__version__ = '2.0.9' +__version__ = "2.0.9" diff --git a/pdm.lock b/pdm.lock index c3953ad..a0d16a6 100644 --- a/pdm.lock +++ b/pdm.lock @@ -8,6 +8,12 @@ name = "certifi" version = "2021.10.8" summary = "Python package for providing Mozilla's CA Bundle." +[[package]] +name = "cfgv" +version = "3.3.1" +requires_python = ">=3.6.1" +summary = "Validate configuration and produce human readable error messages." + [[package]] name = "charset-normalizer" version = "2.0.11" @@ -70,6 +76,11 @@ dependencies = [ "requests", ] +[[package]] +name = "distlib" +version = "0.3.4" +summary = "Distribution utilities" + [[package]] name = "efb-qq-slave" version = "2.0.1.dev0" @@ -99,6 +110,12 @@ dependencies = [ "typing-extensions", ] +[[package]] +name = "filelock" +version = "3.4.2" +requires_python = ">=3.7" +summary = "A platform independent file lock." + [[package]] name = "flask" version = "2.0.2" @@ -111,6 +128,12 @@ dependencies = [ "itsdangerous>=2.0", ] +[[package]] +name = "identify" +version = "2.4.8" +requires_python = ">=3.7" +summary = "File identification library for Python" + [[package]] name = "idna" version = "3.3" @@ -208,12 +231,23 @@ version = "8.12.0" requires_python = ">=3.5" summary = "More routines for operating on iterables, beyond itertools" +[[package]] +name = "nodeenv" +version = "1.6.0" +summary = "Node.js virtual environment builder" + [[package]] name = "pillow" version = "9.0.1" requires_python = ">=3.7" summary = "Python Imaging Library (Fork)" +[[package]] +name = "platformdirs" +version = "2.4.1" +requires_python = ">=3.7" +summary = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." + [[package]] name = "portend" version = "3.1.0" @@ -223,6 +257,21 @@ dependencies = [ "tempora>=1.8", ] +[[package]] +name = "pre-commit" +version = "2.17.0" +requires_python = ">=3.6.1" +summary = "A framework for managing and maintaining multi-language pre-commit hooks." +dependencies = [ + "cfgv>=2.0.0", + "identify>=1.0.0", + "importlib-metadata; python_version < \"3.8\"", + "nodeenv>=0.11.1", + "pyyaml>=5.1", + "toml", + "virtualenv>=20.0.8", +] + [[package]] name = "python-magic" version = "0.4.25" @@ -294,6 +343,12 @@ dependencies = [ "pytz", ] +[[package]] +name = "toml" +version = "0.10.2" +requires_python = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +summary = "Python Library for Tom's Obvious, Minimal Language" + [[package]] name = "typing-extensions" version = "4.0.1" @@ -306,6 +361,19 @@ version = "1.26.8" requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" summary = "HTTP library with thread-safe connection pooling, file post, and more." +[[package]] +name = "virtualenv" +version = "20.13.0" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +summary = "Virtual Python Environment builder" +dependencies = [ + "distlib<1,>=0.3.1", + "filelock<4,>=3.2", + "importlib-metadata>=0.12; python_version < \"3.8\"", + "platformdirs<3,>=2", + "six<2,>=1.9.0", +] + [[package]] name = "werkzeug" version = "2.0.2" @@ -328,7 +396,7 @@ summary = "Backport of pathlib-compatible object wrapper for zip files" [metadata] lock_version = "3.1" -content_hash = "sha256:0e2a42ddc2fd648d8001d7be1ebfedbae88d34a2a78de0d941a23637dd7199dd" +content_hash = "sha256:63656839bd77b534cd7236e11ac80dcbb103f86659970673c7bba62c02f393c3" [metadata.files] "bullet 2.2.0" = [ @@ -339,6 +407,10 @@ content_hash = "sha256:0e2a42ddc2fd648d8001d7be1ebfedbae88d34a2a78de0d941a23637d {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, ] +"cfgv 3.3.1" = [ + {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, + {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, +] "charset-normalizer 2.0.11" = [ {file = "charset_normalizer-2.0.11-py3-none-any.whl", hash = "sha256:2842d8f5e82a1f6aa437380934d5e1cd4fcf2003b06fed6940769c164a480a45"}, {file = "charset-normalizer-2.0.11.tar.gz", hash = "sha256:98398a9d69ee80548c762ba991a4728bfc3836768ed226b3945908d1a688371c"}, @@ -366,14 +438,26 @@ content_hash = "sha256:0e2a42ddc2fd648d8001d7be1ebfedbae88d34a2a78de0d941a23637d "cqhttp 1.3.1" = [ {file = "cqhttp-1.3.1.tar.gz", hash = "sha256:4cb0dae03872162df395ef49f3bb2ec69501cc0d686193dfb1b413097b062821"}, ] +"distlib 0.3.4" = [ + {file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"}, + {file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"}, +] "ehforwarderbot 2.1.1" = [ {file = "ehforwarderbot-2.1.1-py3-none-any.whl", hash = "sha256:33e02015cc7dabde9d7e719a6486ccedd681e33246ab746d5ed6de4ec9b96dac"}, {file = "ehforwarderbot-2.1.1.tar.gz", hash = "sha256:414c3de4e9ad151d3ad38d37d89f0b626a5fa7fb04d9d30ff152b5230d34099b"}, ] +"filelock 3.4.2" = [ + {file = "filelock-3.4.2-py3-none-any.whl", hash = "sha256:cf0fc6a2f8d26bd900f19bf33915ca70ba4dd8c56903eeb14e1e7a2fd7590146"}, + {file = "filelock-3.4.2.tar.gz", hash = "sha256:38b4f4c989f9d06d44524df1b24bd19e167d851f19b50bf3e3559952dddc5b80"}, +] "flask 2.0.2" = [ {file = "Flask-2.0.2-py3-none-any.whl", hash = "sha256:cb90f62f1d8e4dc4621f52106613488b5ba826b2e1e10a33eac92f723093ab6a"}, {file = "Flask-2.0.2.tar.gz", hash = "sha256:7b2fb8e934ddd50731893bdcdb00fc8c0315916f9fcd50d22c7cc1a95ab634e2"}, ] +"identify 2.4.8" = [ + {file = "identify-2.4.8-py2.py3-none-any.whl", hash = "sha256:a55bdd671b6063eb837af938c250ec00bba6e610454265133b0d2db7ae718d0f"}, + {file = "identify-2.4.8.tar.gz", hash = "sha256:97e839c1779f07011b84c92af183e1883d9745d532d83412cca1ca76d3808c1c"}, +] "idna 3.3" = [ {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, @@ -489,6 +573,10 @@ content_hash = "sha256:0e2a42ddc2fd648d8001d7be1ebfedbae88d34a2a78de0d941a23637d {file = "more_itertools-8.12.0-py3-none-any.whl", hash = "sha256:43e6dd9942dffd72661a2c4ef383ad7da1e6a3e968a927ad7a6083ab410a688b"}, {file = "more-itertools-8.12.0.tar.gz", hash = "sha256:7dc6ad46f05f545f900dd59e8dfb4e84a4827b97b3cfecb175ea0c7d247f6064"}, ] +"nodeenv 1.6.0" = [ + {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"}, + {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"}, +] "pillow 9.0.1" = [ {file = "Pillow-9.0.1-1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a5d24e1d674dd9d72c66ad3ea9131322819ff86250b30dc5821cbafcfa0b96b4"}, {file = "Pillow-9.0.1-1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2632d0f846b7c7600edf53c48f8f9f1e13e62f66a6dbc15191029d950bfed976"}, @@ -526,10 +614,18 @@ content_hash = "sha256:0e2a42ddc2fd648d8001d7be1ebfedbae88d34a2a78de0d941a23637d {file = "Pillow-9.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a9f44cd7e162ac6191491d7249cceb02b8116b0f7e847ee33f739d7cb1ea1f70"}, {file = "Pillow-9.0.1.tar.gz", hash = "sha256:6c8bc8238a7dfdaf7a75f5ec5a663f4173f8c367e5a39f87e720495e1eed75fa"}, ] +"platformdirs 2.4.1" = [ + {file = "platformdirs-2.4.1-py3-none-any.whl", hash = "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca"}, + {file = "platformdirs-2.4.1.tar.gz", hash = "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"}, +] "portend 3.1.0" = [ {file = "portend-3.1.0-py3-none-any.whl", hash = "sha256:9e735cee3a5c1961f09e3f3ba6dc498198c2d70b473d98d0d1504b8d1e7a3d61"}, {file = "portend-3.1.0.tar.gz", hash = "sha256:239e3116045ea823f6df87d6168107ad75ccc0590e37242af0cc1e98c5d224e4"}, ] +"pre-commit 2.17.0" = [ + {file = "pre_commit-2.17.0-py2.py3-none-any.whl", hash = "sha256:725fa7459782d7bec5ead072810e47351de01709be838c2ce1726b9591dad616"}, + {file = "pre_commit-2.17.0.tar.gz", hash = "sha256:c1a8040ff15ad3d648c70cc3e55b93e4d2d5b687320955505587fd79bbaed06a"}, +] "python-magic 0.4.25" = [ {file = "python_magic-0.4.25-py2.py3-none-any.whl", hash = "sha256:1a2c81e8f395c744536369790bd75094665e9644110a6623bcc3bbea30f03973"}, {file = "python-magic-0.4.25.tar.gz", hash = "sha256:21f5f542aa0330f5c8a64442528542f6215c8e18d2466b399b0d9d39356d83fc"}, @@ -634,6 +730,10 @@ content_hash = "sha256:0e2a42ddc2fd648d8001d7be1ebfedbae88d34a2a78de0d941a23637d {file = "tempora-5.0.1-py3-none-any.whl", hash = "sha256:fbca6a229af666ea4ea8b2f9f80ac9a074f7cf53a97987855b1d15b6e93fd63b"}, {file = "tempora-5.0.1.tar.gz", hash = "sha256:cba0f197a64883bf3e73657efbc0324d5bf17179e7769b1385b4d75d26cd9127"}, ] +"toml 0.10.2" = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] "typing-extensions 4.0.1" = [ {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"}, {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"}, @@ -642,6 +742,10 @@ content_hash = "sha256:0e2a42ddc2fd648d8001d7be1ebfedbae88d34a2a78de0d941a23637d {file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"}, {file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"}, ] +"virtualenv 20.13.0" = [ + {file = "virtualenv-20.13.0-py2.py3-none-any.whl", hash = "sha256:339f16c4a86b44240ba7223d0f93a7887c3ca04b5f9c8129da7958447d079b09"}, + {file = "virtualenv-20.13.0.tar.gz", hash = "sha256:d8458cf8d59d0ea495ad9b34c2599487f8a7772d796f9910858376d1600dd2dd"}, +] "werkzeug 2.0.2" = [ {file = "Werkzeug-2.0.2-py3-none-any.whl", hash = "sha256:63d3dc1cf60e7b7e35e97fa9861f7397283b75d765afcaefd993d6046899de8f"}, {file = "Werkzeug-2.0.2.tar.gz", hash = "sha256:aa2bb6fc8dee8d6c504c0ac1e7f5f7dc5810a9903e793b6f715a9f015bdadb9a"}, diff --git a/pyproject.toml b/pyproject.toml index e616f88..389b5d0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,10 +46,20 @@ homepage = "https://github.com/ehForwarderBot/efb-qq-plugin-go-cqhttp" [project.entry-points."ehforwarderbot.qq.plugin"] GoCQHttp = "efb_qq_plugin_go_cqhttp:GoCQHttp" -[tool] -[tool.pdm] -version = { from = "efb_qq_plugin_go_cqhttp/__init__.py" } - [build-system] requires = ["pdm-pep517"] build-backend = "pdm.pep517.api" + +[tool.pdm] +version = { from = "efb_qq_plugin_go_cqhttp/__init__.py" } + +[tool.pdm.dev-dependencies] +dev = ["pre-commit"] + +[tool.black] +line-length = 120 + +[tool.isort] +profile = "black" +atomic = true +filter_files = true