diff --git a/README.md b/README.md index 889419d..0831dd4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

NtChat

- release + release License

diff --git a/examples/echo_bot_image.py b/examples/echo_bot_image.py new file mode 100644 index 0000000..5cc6961 --- /dev/null +++ b/examples/echo_bot_image.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +import sys +import time +import ntchat + +wechat = ntchat.WeChat() + +# 打开pc微信, smart: 是否管理已经登录的微信 +wechat.open(smart=True) + + +# 注册消息回调 +@wechat.msg_register(ntchat.MT_RECV_PICTURE_MSG) +def on_recv_text_msg(wechat_instance: ntchat.WeChat, message): + data = message["data"] + from_wxid = data["from_wxid"] + self_wxid = wechat_instance.get_login_info()["wxid"] + room_wxid = data["room_wxid"] + + # 判断消息不是自己发的并且不是群消息时,回复对方 + if from_wxid != self_wxid and not room_wxid: + time.sleep(3) + wechat_instance.send_image(to_wxid=from_wxid, file_path=data["image"]) + + +# 以下是为了让程序不结束,如果有用于PyQt等有主循环消息的框架,可以去除下面代码 +try: + while True: + time.sleep(0.5) +except KeyboardInterrupt: + ntchat.exit_() + sys.exit() diff --git a/examples/echo_bot_msg_register.py b/examples/echo_bot_msg_register.py index 6bd29ec..84bf82b 100644 --- a/examples/echo_bot_msg_register.py +++ b/examples/echo_bot_msg_register.py @@ -6,7 +6,6 @@ import ntchat wechat = ntchat.WeChat() # 打开pc微信, smart: 是否管理已经登录的微信 - wechat.open(smart=True) diff --git a/examples/send_text_ui.py b/examples/send_text_ui.py index 5504ec7..daa3842 100644 --- a/examples/send_text_ui.py +++ b/examples/send_text_ui.py @@ -25,6 +25,8 @@ class NtChatWindow(XWindow): def on_btn_open_clicked(self, sender, _): self.wechat_instance = ntchat.WeChat() self.wechat_instance.open(smart=True) + + # 监听所有通知消息 self.wechat_instance.on(ntchat.MT_ALL, self.on_recv_message) def on_btn_send_clicked(self, sender, _): diff --git a/ntchat/__init__.py b/ntchat/__init__.py index 437b2cb..b641727 100644 --- a/ntchat/__init__.py +++ b/ntchat/__init__.py @@ -1,9 +1,19 @@ from .conf import VERSION from .core.wechat import WeChat from .wc import wcprobe -from .const.wx_type import * +from .const.notify_type import * from .exception import * +from . import conf __version__ = VERSION + +def set_wechat_exe_path(wechat_exe_path=None, wechat_version=None): + """ + 自定义微信路径 + """ + conf.DEFAULT_WECHAT_EXE_PATH = wechat_exe_path + conf.DEFAULT_WECHAT_VERSION = wechat_version + + exit_ = wcprobe.exit diff --git a/ntchat/conf/__init__.py b/ntchat/conf/__init__.py index 856ce1d..9cab2c0 100644 --- a/ntchat/conf/__init__.py +++ b/ntchat/conf/__init__.py @@ -1 +1,9 @@ -VERSION = '0.1.2' +VERSION = '0.1.3' + +LOG_LEVEL = "DEBUG" +LOG_KEY = 'NTCHAT_LOG' +LOG_FILE_KEY = 'NTCHAT_LOG_FILE' + +DEFAULT_WECHAT_EXE_PATH = None +DEFAULT_WECHAT_VERSION = None + diff --git a/ntchat/const/notify_type.py b/ntchat/const/notify_type.py new file mode 100644 index 0000000..0d321b0 --- /dev/null +++ b/ntchat/const/notify_type.py @@ -0,0 +1,66 @@ +# 用于接收所有的通知消息 +MT_ALL = 11000 + +# 第个通知消息,此时已经托管上微信 +MT_READY_MSG = 11024 + +# 登录二维码通知 +MT_RECV_LOGIN_QRCODE_MSG = 11087 + +# 用户登录成功的通知 +MT_USER_LOGIN_MSG = 11025 + +# 用户注销或退出微信的通知 +MT_USER_LOGOUT_MSG = 11026 + +# 文本消息通知 +MT_RECV_TEXT_MSG = 11046 + +# 图片消息通知 +MT_RECV_IMAGE_MSG = 11047 +MT_RECV_PICTURE_MSG = 11047 + +# 语音消息通知 +MT_RECV_VOICE_MSG = 11048 + +# 新好友请求通知 +MT_RECV_FRIEND_MSG = 11049 + +# 好友分享名片通知 +MT_RECV_CARD_MSG = 11050 + +# 视频消息通知 +MT_RECV_VIDEO_MSG = 11051 + +# 表情消息通知 +MT_RECV_EMOJI_MSG = 11052 + +# 位置消息通知 +MT_RECV_LOCATION_MSG = 11053 + +# 链接卡片消息通知 +MT_RECV_LINK_MSG = 11054 + +# 文件消息通知 +MT_RECV_FILE_MSG = 11055 + +# 小程序消息通知 +MT_RECV_MINIAPP_MSG = 11056 + +# 二维码支付通知 +MT_RECV_WCPAY_MSG = 11057 + +# 系统消息通知 +MT_RECV_SYSTEM_MSG = 11058 + +# 撤回消息通知 +MT_RECV_REVOKE_MSG = 11059 + +# 未知消息通知 +MT_RECV_OTHER_MSG = 11060 + +# 未知应用消息通知 +MT_RECV_OTHER_APP_MSG = 11061 + + + diff --git a/ntchat/const/send_type.py b/ntchat/const/send_type.py new file mode 100644 index 0000000..6a9032c --- /dev/null +++ b/ntchat/const/send_type.py @@ -0,0 +1,65 @@ +# 获取自己的帐号信息 +MT_GET_SELF_MSG = 11028 + +# 获取所有的联系人 +MT_GET_CONTACTS_MSG = 11030 + +# 获取所有的群 +MT_GET_ROOMS_MSG = 11031 + +# 获取指定的群成员 +MT_GET_ROOM_MEMBERS_MSG = 11032 + +# 获取指定联系人的详细信息 +MT_GET_CONTACT_DETAIL_MSG = 11034 + +# 发送文本消息 +MT_SEND_TEXT_MSG = 11036 + +# 发送群@消息 +MT_SEND_ROOM_AT_MSG = 11037 + +# 发送名片消息 +MT_SEND_CARD_MSG = 11038 + +# 发送链接卡片消息 +MT_SEND_LINK_MSG = 11039 + +# 发送图片消息 +MT_SEND_IMAGE_MSG = 11040 + +# 发送文件消息 +MT_SEND_FILE_MSG = 11041 + +# 发送视频消息 +MT_SEND_VIDEO_MSG = 11042 + +# 发送gif消息 +MT_SEND_GIF_MSG = 11043 + +# 接受新好友请求 +MT_ACCEPT_FRIEND_MSG = 11065 + +# 创建群 +MT_CREATE_ROOM_MSG = 11068 + +# 添加好友进群 +MT_ADD_TO_ROOM_MSG = 11069 + +# 邀请好友进群 +MT_INVITE_TO_ROOM_MSG = 11070 + +# 移除群成员 +MT_DEL_ROOM_MEMBER_MSG = 11071 + +# 修改群名 +MT_MOD_ROOM_NAME_MSG = 11072 + +# 修改群公告 +MT_MOD_ROOM_NOTICE_MSG = 11073 + +# 退出群 +MT_QUIT_DEL_ROOM_MSG = 11077 + +# 添加群成员为好友 +MT_ADD_FRIEND_MSG = 11062 diff --git a/ntchat/const/wx_type.py b/ntchat/const/wx_type.py deleted file mode 100644 index 538ddab..0000000 --- a/ntchat/const/wx_type.py +++ /dev/null @@ -1,50 +0,0 @@ -MT_ALL = 11000 -MT_READY_MSG = 11024 -MT_USER_LOGIN_MSG = 11025 -MT_USER_LOGOUT_MSG = 11026 -MT_GET_SELF_MSG = 11028 -MT_GET_CONTACTS_MSG = 11030 -MT_GET_ROOMS_MSG = 11031 -MT_GET_ROOM_MEMBERS_MSG = 11032 -MT_GET_CONTACT_DETAIL_MSG = 11034 - -# 发送消息 -MT_SEND_TEXT_MSG = 11036 -MT_SEND_ROOM_AT_MSG = 11037 -MT_SEND_CARD_MSG = 11038 -MT_SEND_LINK_MSG = 11039 -MT_SEND_IMAGE_MSG = 11040 -MT_SEND_FILE_MSG = 11041 -MT_SEND_VIDEO_MSG = 11042 -MT_SEND_GIF_MSG = 11043 - -# 接收消息类 -MT_RECV_TEXT_MSG = 11046 -MT_RECV_PICTURE_MSG = 11047 -MT_RECV_VOICE_MSG = 11048 -MT_RECV_FRIEND_MSG = 11049 -MT_RECV_CARD_MSG = 11050 -MT_RECV_VIDEO_MSG = 11051 -MT_RECV_EMOJI_MSG = 11052 -MT_RECV_LOCATION_MSG = 11053 -MT_RECV_LINK_MSG = 11054 -MT_RECV_FILE_MSG = 11055 -MT_RECV_MINIAPP_MSG = 11056 -MT_RECV_WCPAY_MSG = 11057 -MT_RECV_SYSTEM_MSG = 11058 -MT_RECV_REVOKE_MSG = 11059 -MT_RECV_OTHER_MSG = 11060 -MT_RECV_OTHER_APP_MSG = 11061 - -# 好友操作 -MT_ACCEPT_FRIEND_MSG = 11065 - -# 群操作类 -MT_CREATE_ROOM_MSG = 11068 -MT_INVITE_TO_ROOM_MSG = 11069 -MT_INVITE_TO_ROOM_REQ_MSG = 11070 -MT_DEL_ROOM_MEMBER_MSG = 11071 -MT_MOD_ROOM_NAME_MSG = 11072 -MT_MOD_ROOM_NOTICE_MSG = 11073 -MT_QUIT_DEL_ROOM_MSG = 11077 - diff --git a/ntchat/core/mgr.py b/ntchat/core/mgr.py index cc4cab5..192de18 100644 --- a/ntchat/core/mgr.py +++ b/ntchat/core/mgr.py @@ -4,8 +4,9 @@ from ntchat.wc import wcprobe from ntchat.utils.xdg import get_helper_file from ntchat.exception import WeChatVersionNotMatchError, WeChatBindError from ntchat.utils.singleton import Singleton -from ntchat.const import wx_type +from ntchat.const import notify_type from ntchat.utils.logger import get_logger +from ntchat import conf log = get_logger("WeChatManager") @@ -14,8 +15,8 @@ class WeChatMgr(metaclass=Singleton): __instance_list = [] __instance_map = {} - def __init__(self, wechat_exe_path=None, wechat_version=None): - self.set_wechat_exe_path(wechat_exe_path, wechat_version) + def __init__(self): + self.set_wechat_exe_path(conf.DEFAULT_WECHAT_EXE_PATH, conf.DEFAULT_WECHAT_VERSION) # init callbacks wcprobe.init_callback(self.__on_accept, self.__on_recv, self.__on_close) @@ -62,7 +63,7 @@ class WeChatMgr(metaclass=Singleton): def __on_recv(self, client_id, data): message = json.loads(data) - if message["type"] == wx_type.MT_READY_MSG: + if message["type"] == notify_type.MT_READY_MSG: self.__bind_wechat(client_id, message["data"]["pid"]) else: self.__instance_map[client_id].on_recv(message) diff --git a/ntchat/core/wechat.py b/ntchat/core/wechat.py index 921d71a..c9ebfa9 100644 --- a/ntchat/core/wechat.py +++ b/ntchat/core/wechat.py @@ -1,7 +1,7 @@ import pyee import json from ntchat.core.mgr import WeChatMgr -from ntchat.const import wx_type +from ntchat.const import notify_type, send_type from threading import Event from ntchat.wc import wcprobe from ntchat.utils import generate_guid @@ -72,12 +72,12 @@ class WeChat: log.debug("on recv message: %s", message) msg_type = message["type"] extend = message.get("extend", None) - if msg_type == wx_type.MT_USER_LOGIN_MSG: + if msg_type == notify_type.MT_USER_LOGIN_MSG: self.login_status = True self.__wait_login_event.set() self.__login_info = message.get("data", {}) log.info("login success, wxid: %s, nickname: %s", self.__login_info["wxid"], self.__login_info["nickname"]) - elif msg_type == wx_type.MT_USER_LOGOUT_MSG: + elif msg_type == notify_type.MT_USER_LOGOUT_MSG: self.login_status = False log.info("logout, pid: %d", self.pid) @@ -87,7 +87,7 @@ class WeChat: del self.__req_data_cache[extend] else: self.__msg_event_emitter.emit(str(msg_type), self, message) - self.__msg_event_emitter.emit(str(wx_type.MT_ALL), self, message) + self.__msg_event_emitter.emit(str(notify_type.MT_ALL), self, message) def wait_login(self, timeout=None): log.info("wait login...") @@ -147,25 +147,25 @@ class WeChat: """ 获取自己个人信息跟登录信息类似 """ - return self.__send_sync(wx_type.MT_GET_SELF_MSG) + return self.__send_sync(send_type.MT_GET_SELF_MSG) def get_contacts(self): """ 获取联系人列表 """ - return self.__send_sync(wx_type.MT_GET_CONTACTS_MSG) + return self.__send_sync(send_type.MT_GET_CONTACTS_MSG) def get_contact_detail(self, wxid): data = { "wxid": wxid } - return self.__send_sync(wx_type.MT_GET_CONTACT_DETAIL_MSG, data) + return self.__send_sync(send_type.MT_GET_CONTACT_DETAIL_MSG, data) def get_rooms(self): """ 获取群列表 """ - return self.__send_sync(wx_type.MT_GET_ROOMS_MSG) + return self.__send_sync(send_type.MT_GET_ROOMS_MSG) def get_room_members(self, room_wxid: str): """ @@ -174,7 +174,7 @@ class WeChat: data = { "room_wxid": room_wxid } - return self.__send_sync(wx_type.MT_GET_ROOM_MEMBERS_MSG, data) + return self.__send_sync(send_type.MT_GET_ROOM_MEMBERS_MSG, data) def send_text(self, to_wxid: str, content: str): """ @@ -184,7 +184,7 @@ class WeChat: "to_wxid": to_wxid, "content": content } - return self.__send(wx_type.MT_SEND_TEXT_MSG, data) + return self.__send(send_type.MT_SEND_TEXT_MSG, data) def send_room_at_msg(self, to_wxid: str, content: str, at_list: List[str]): """ @@ -195,7 +195,7 @@ class WeChat: 'content': content, 'at_list': at_list } - return self.__send(wx_type.MT_SEND_ROOM_AT_MSG, data) + return self.__send(send_type.MT_SEND_ROOM_AT_MSG, data) def send_card(self, to_wxid: str, card_wxid: str): """ @@ -205,7 +205,7 @@ class WeChat: 'to_wxid': to_wxid, 'card_wxid': card_wxid } - return self.__send(wx_type.MT_SEND_CARD_MSG, data) + return self.__send(send_type.MT_SEND_CARD_MSG, data) def send_link_card(self, to_wxid: str, title: str, desc: str, url: str, image_url: str): """ @@ -218,7 +218,7 @@ class WeChat: 'url': url, 'image_url': image_url } - return self.__send(wx_type.MT_SEND_LINK_MSG, data) + return self.__send(send_type.MT_SEND_LINK_MSG, data) def send_image(self, to_wxid: str, file_path: str): """ @@ -228,7 +228,7 @@ class WeChat: 'to_wxid': to_wxid, 'file': file_path } - return self.__send(wx_type.MT_SEND_IMAGE_MSG, data) + return self.__send(send_type.MT_SEND_IMAGE_MSG, data) def send_file(self, to_wxid: str, file_path: str): """ @@ -238,7 +238,7 @@ class WeChat: 'to_wxid': to_wxid, 'file': file_path } - return self.__send(wx_type.MT_SEND_FILE_MSG, data) + return self.__send(send_type.MT_SEND_FILE_MSG, data) # def send_video(self, to_wxid: str, file_path: str): @@ -249,7 +249,7 @@ class WeChat: 'to_wxid': to_wxid, 'file': file_path } - return self.__send(wx_type.MT_SEND_VIDEO_MSG, data) + return self.__send(send_type.MT_SEND_VIDEO_MSG, data) def send_gif(self, to_wxid, file): """ @@ -259,7 +259,7 @@ class WeChat: 'to_wxid': to_wxid, 'file': file } - return self.__send(wx_type.MT_SEND_GIF_MSG, data) + return self.__send(send_type.MT_SEND_GIF_MSG, data) def accept_friend_request(self, encryptusername: str, ticket: str, scene: int): """ @@ -270,13 +270,13 @@ class WeChat: "ticket": ticket, "scene": scene } - return self.__send_sync(wx_type.MT_ACCEPT_FRIEND_MSG, data) + return self.__send_sync(send_type.MT_ACCEPT_FRIEND_MSG, data) def create_room(self, member_list: List[str]): """ 创建群 """ - return self.__send(wx_type.MT_CREATE_ROOM_MSG, member_list) + return self.__send(send_type.MT_CREATE_ROOM_MSG, member_list) def add_room_member(self, room_wxid: str, member_list: List[str]): """ @@ -286,7 +286,7 @@ class WeChat: "room_wxid": room_wxid, "member_list": member_list } - return self.__send_sync(wx_type.MT_INVITE_TO_ROOM_MSG, data) + return self.__send_sync(send_type.MT_ADD_TO_ROOM_MSG, data) def invite_room_member(self, room_wxid: str, member_list: List[str]): """ @@ -296,7 +296,7 @@ class WeChat: "room_wxid": room_wxid, "member_list": member_list } - return self.__send_sync(wx_type.MT_INVITE_TO_ROOM_REQ_MSG, data) + return self.__send_sync(send_type.MT_INVITE_TO_ROOM_MSG, data) def del_room_member(self, room_wxid: str, member_list: List[str]): """ @@ -306,7 +306,7 @@ class WeChat: "room_wxid": room_wxid, "member_list": member_list } - return self.__send_sync(wx_type.MT_DEL_ROOM_MEMBER_MSG, data) + return self.__send_sync(send_type.MT_DEL_ROOM_MEMBER_MSG, data) def modify_room_name(self, room_wxid: str, name: str): """ @@ -316,7 +316,7 @@ class WeChat: "room_wxid": room_wxid, "name": name } - return self.__send_sync(wx_type.MT_MOD_ROOM_NAME_MSG, data) + return self.__send_sync(send_type.MT_MOD_ROOM_NAME_MSG, data) def modify_room_notice(self, room_wxid: str, notice: str): """ @@ -326,6 +326,17 @@ class WeChat: "room_wxid": room_wxid, "notice": notice } - return self.__send_sync(wx_type.MT_MOD_ROOM_NOTICE_MSG, data) + return self.__send_sync(send_type.MT_MOD_ROOM_NAME_MSG, data) + def add_room_friend(self, room_wxid: str, wxid: str, verify: str): + """ + 添加群成员为好友 + """ + data = { + "room_wxid": room_wxid, + "wxid": wxid, + "source_type": 14, + "remark": verify + } + return self.__send_sync(send_type.MT_ADD_FRIEND_MSG, data) diff --git a/ntchat/utils/logger.py b/ntchat/utils/logger.py index 09d5477..f5675a5 100644 --- a/ntchat/utils/logger.py +++ b/ntchat/utils/logger.py @@ -1,42 +1,27 @@ -import logging import os -import configparser +import logging from datetime import datetime -from .xdg import get_log_dir, get_exec_dir - -NTCHAT_LOG_KEY = 'NTCHAT_LOG' -NTCHAT_LOG_FILE_KEY = 'NTCHAT_LOG_FILE' - - -config_file = os.path.join(get_exec_dir(), "config.ini") -CONFIG_DEBUG_LEVEL = '' - -if os.path.exists(config_file): - config = configparser.ConfigParser() - config.read(config_file) - CONFIG_DEBUG_LEVEL = config.get('Config', 'LogLevel', fallback=CONFIG_DEBUG_LEVEL) +from .xdg import get_log_dir +from .. import conf def get_logger(name: str) -> logging.Logger: """ configured Loggers """ - NTCHAT_LOG = os.environ.get(NTCHAT_LOG_KEY, 'DEBUG') + log_level = os.environ.get(conf.LOG_KEY, conf.LOG_LEVEL) log_formatter = logging.Formatter( fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s') - if CONFIG_DEBUG_LEVEL: - NTCHAT_LOG = CONFIG_DEBUG_LEVEL - # create logger and set level to debug logger = logging.getLogger(name) logger.handlers = [] - logger.setLevel(NTCHAT_LOG) + logger.setLevel(log_level) logger.propagate = False # create file handler and set level to debug - if NTCHAT_LOG_FILE_KEY in os.environ: - filepath = os.environ[NTCHAT_LOG_FILE_KEY] + if conf.LOG_FILE_KEY in os.environ: + filepath = os.environ[conf.LOG_FILE_KEY] else: base_dir = get_log_dir() if not os.path.exists(base_dir): @@ -48,13 +33,13 @@ def get_logger(name: str) -> logging.Logger: filepath = f'{base_dir}/log-{time_now.strftime(time_format)}.txt' file_handler = logging.FileHandler(filepath, 'a', encoding='utf-8') - file_handler.setLevel(NTCHAT_LOG) + file_handler.setLevel(log_level) file_handler.setFormatter(log_formatter) logger.addHandler(file_handler) # create console handler and set level to info console_handler = logging.StreamHandler() - console_handler.setLevel(NTCHAT_LOG) + console_handler.setLevel(log_level) console_handler.setFormatter(log_formatter) logger.addHandler(console_handler) diff --git a/setup.py b/setup.py index 7da4a00..e7b2202 100644 --- a/setup.py +++ b/setup.py @@ -194,7 +194,7 @@ extension.extra_compile_cpp_args = extra_compile_cpp_args[target_os] setup( name='ntchat', - version='0.1.2', + version='0.1.3', description='About Conversational RPA SDK for Chatbot Makers', long_description="", long_description_content_type='text/markdown',