Compare commits

..

No commits in common. "master" and "v0.1.15" have entirely different histories.

14 changed files with 68 additions and 93 deletions

View File

@ -1,6 +1,6 @@
<h1 align="center">NtChat</h1> <h1 align="center">NtChat</h1>
<p align="center"> <p align="center">
<a href="https://github.com/smallevilbeast/ntchat/releases"><img src="https://img.shields.io/badge/release-0.1.17-blue.svg?" alt="release"></a> <a href="https://github.com/smallevilbeast/ntchat/releases"><img src="https://img.shields.io/badge/release-0.1.15-blue.svg?" alt="release"></a>
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-brightgreen.svg?" alt="License"></a> <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-brightgreen.svg?" alt="License"></a>
</p> </p>
@ -20,6 +20,7 @@
- 查看 [常见问题](docs/FAQ.md) - 查看 [常见问题](docs/FAQ.md)
- 查看 [常用示例](examples) - 查看 [常用示例](examples)
- 查看 [NtChatHttp接口示例](fastapi_example) - 查看 [NtChatHttp接口示例](fastapi_example)
- 加入群聊 [PyXCGUI&NtChat交流群](https://jq.qq.com/?_wv=1027&k=oIXzbTbI)
- 查看 [PyXCGUI项目](https://github.com/smallevilbeast/pyxcgui) - 查看 [PyXCGUI项目](https://github.com/smallevilbeast/pyxcgui)
## 安装 ## 安装
@ -201,3 +202,7 @@ if __name__ == '__main__':
app.exit() app.exit()
``` ```
帮助&支持
-------------------------
点击链接加入群聊 [PyXCGUI&NtChat交流群](https://jq.qq.com/?_wv=1027&k=oIXzbTbI)

34
examples/sql_query.py Normal file
View File

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
import sys
import time
import ntchat
wechat = ntchat.WeChat()
# 打开pc微信, smart: 是否管理已经登录的微信
wechat.open(smart=True)
# 等待登录
wechat.wait_login()
# 获取群列表并输出
room_wxid = wechat.get_rooms()[0]["wxid"]
def get_room_name(wechat: ntchat.WeChat, room_wxid: str):
sql = f"select nickname from contact where username='{room_wxid}'"
result = wechat.sql_query(sql, 1)["result"]
if result:
return result[0][0]
return None
print("群名是: ", get_room_name(wechat, room_wxid))
# 以下是为了让程序不结束如果有用于PyQt等有主循环消息的框架可以去除下面代码
try:
while True:
time.sleep(0.5)
except KeyboardInterrupt:
ntchat.exit_()
sys.exit()

View File

@ -1,6 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import uvicorn import uvicorn
import threading
from functools import wraps from functools import wraps
from fastapi import FastAPI from fastapi import FastAPI
from mgr import ClientManager from mgr import ClientManager
@ -57,14 +56,8 @@ async def client_create():
response_model=models.ResponseModel) response_model=models.ResponseModel)
@catch_exception() @catch_exception()
async def client_open(model: models.ClientOpenReqModel): async def client_open(model: models.ClientOpenReqModel):
client = client_mgr.get_client(model.guid) ret = client_mgr.get_client(model.guid).open(model.smart, model.show_login_qrcode)
ret = client.open(model.smart, model.show_login_qrcode) return response_json(1 if ret else 0)
# 当show_login_qrcode=True时, 打开微信时会显示二维码界面
if model.show_login_qrcode:
client.qrcode_event = threading.Event()
client.qrcode_event.wait(timeout=10)
return response_json(1 if ret else 0, {'qrcode': client.qrcode})
@app.post("/global/set_callback_url", summary="设置接收通知地址", tags=["Global"], @app.post("/global/set_callback_url", summary="设置接收通知地址", tags=["Global"],
@ -114,17 +107,6 @@ async def get_rooms(model: models.ClientReqModel):
return response_json(1, data) return response_json(1, data)
@app.post("/room/get_name_name", summary="获取群名称", tags=["Room"],
response_model=models.ResponseModel)
@catch_exception()
async def get_rooms(model: models.GetRoomNameReqModel):
name = client_mgr.get_client(model.guid).get_room_name(model.room_wxid)
data = {
"name": name
}
return response_json(1, data)
@app.post("/room/get_room_members", summary="获取群成员列表", tags=["Room"], @app.post("/room/get_room_members", summary="获取群成员列表", tags=["Room"],
response_model=models.ResponseModel) response_model=models.ResponseModel)
@catch_exception() @catch_exception()

View File

@ -1,6 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import ntchat import ntchat
import threading
import requests import requests
from typing import Dict, Union from typing import Dict, Union
from ntchat.utils.singleton import Singleton from ntchat.utils.singleton import Singleton
@ -10,8 +9,6 @@ from exception import ClientNotExists
class ClientWeChat(ntchat.WeChat): class ClientWeChat(ntchat.WeChat):
guid: str = "" guid: str = ""
qrcode_event: threading.Event = None
qrcode: str = ""
class ClientManager(metaclass=Singleton): class ClientManager(metaclass=Singleton):
@ -38,7 +35,7 @@ class ClientManager(metaclass=Singleton):
wechat.on(ntchat.MT_RECV_WECHAT_QUIT_MSG, self.__on_quit_callback) wechat.on(ntchat.MT_RECV_WECHAT_QUIT_MSG, self.__on_quit_callback)
return guid return guid
def get_client(self, guid: str) -> ClientWeChat: def get_client(self, guid: str) -> Union[None, ntchat.WeChat]:
client = self.__client_map.get(guid, None) client = self.__client_map.get(guid, None)
if client is None: if client is None:
raise ClientNotExists(guid) raise ClientNotExists(guid)
@ -48,14 +45,7 @@ class ClientManager(metaclass=Singleton):
if guid in self.__client_map: if guid in self.__client_map:
del self.__client_map[guid] del self.__client_map[guid]
def __on_callback(self, wechat: ClientWeChat, message: dict): def __on_callback(self, wechat, message):
# 通知二维码显示
msg_type = message['type']
if msg_type == ntchat.MT_RECV_LOGIN_QRCODE_MSG and wechat.qrcode_event:
wechat.qrcode = message["data"]["code"]
wechat.qrcode_event.set()
if not self.callback_url: if not self.callback_url:
return return

View File

@ -87,10 +87,6 @@ class GetRoomMembersReqModel(ClientReqModel):
room_wxid: str room_wxid: str
class GetRoomNameReqModel(ClientReqModel):
room_wxid: str
class CreateRoomReqModel(ClientReqModel): class CreateRoomReqModel(ClientReqModel):
member_list: List[str] member_list: List[str]

View File

@ -1,4 +1,4 @@
VERSION = '0.1.17' VERSION = '0.1.15'
LOG_LEVEL = "DEBUG" LOG_LEVEL = "DEBUG"
LOG_KEY = 'NTCHAT_LOG' LOG_KEY = 'NTCHAT_LOG'

View File

@ -1,8 +1,8 @@
import json import json
import os.path import os.path
from ntchat.wc import wcprobe, SUPPORT_VERSIONS from ntchat.wc import wcprobe
from ntchat.utils.xdg import get_helper_file, is_support_version, has_helper_file from ntchat.utils.xdg import get_helper_file
from ntchat.exception import WeChatVersionNotMatchError, WeChatBindError, WeChatRuntimeError from ntchat.exception import WeChatVersionNotMatchError, WeChatBindError
from ntchat.utils.singleton import Singleton from ntchat.utils.singleton import Singleton
from ntchat.const import notify_type from ntchat.const import notify_type
from ntchat.utils.logger import get_logger from ntchat.utils.logger import get_logger
@ -31,16 +31,9 @@ class WeChatMgr(metaclass=Singleton):
else: else:
version = wechat_version version = wechat_version
if not is_support_version(version):
raise WeChatVersionNotMatchError(f"ntchat support wechat versions: {','.join(SUPPORT_VERSIONS)}")
if not has_helper_file():
raise WeChatRuntimeError('When using pyinstaller to package exe, you need to add the '
'`--collect-data=ntchat` parameter')
helper_file = get_helper_file(version) helper_file = get_helper_file(version)
if not os.path.exists(helper_file): if not os.path.exists(helper_file):
raise WeChatRuntimeError("missing core files") raise WeChatVersionNotMatchError()
log.info("initialize wechat, version: %s", version) log.info("initialize wechat, version: %s", version)

View File

@ -62,32 +62,34 @@ class WeChat:
WeChatMgr().append_instance(self) WeChatMgr().append_instance(self)
self.__wait_login_event = Event() self.__wait_login_event = Event()
self.__req_data_cache = {} self.__req_data_cache = {}
self.event_emitter = pyee.EventEmitter() self.__msg_event_emitter = pyee.EventEmitter()
self.__login_info = {} self.__login_info = {}
def on(self, msg_type, f): def on(self, msg_type, f):
if not (isinstance(msg_type, list) or isinstance(msg_type, tuple)): return self.__msg_event_emitter.on(str(msg_type), RaiseExceptionFunc(f))
msg_type = [msg_type]
for event in msg_type:
self.event_emitter.on(str(event), RaiseExceptionFunc(f))
def msg_register(self, msg_type: Union[int, List[int], Tuple[int]]): def msg_register(self, msg_type: Union[int, List[int], Tuple[int]]):
if not (isinstance(msg_type, list) or isinstance(msg_type, tuple)):
msg_type = [msg_type]
def wrapper(f): def wrapper(f):
wraps(f) wraps(f)
self.on(msg_type, f) for event in msg_type:
self.on(event, RaiseExceptionFunc(f))
return f return f
return wrapper return wrapper
def on_close(self): def on_close(self):
self.login_status = False self.login_status = False
self.status = False self.status = False
self.event_emitter.emit(str(notify_type.MT_RECV_WECHAT_QUIT_MSG), self) self.__msg_event_emitter.emit(str(notify_type.MT_RECV_WECHAT_QUIT_MSG), self)
message = { message = {
"type": notify_type.MT_RECV_WECHAT_QUIT_MSG, "type": notify_type.MT_RECV_WECHAT_QUIT_MSG,
"data": {} "data": {}
} }
self.event_emitter.emit(str(notify_type.MT_ALL), self, message) self.__msg_event_emitter.emit(str(notify_type.MT_ALL), self, message)
def bind_client_id(self, client_id): def bind_client_id(self, client_id):
self.status = True self.status = True
@ -111,8 +113,8 @@ class WeChat:
req_data.on_response(message) req_data.on_response(message)
del self.__req_data_cache[extend] del self.__req_data_cache[extend]
else: else:
self.event_emitter.emit(str(msg_type), self, message) self.__msg_event_emitter.emit(str(msg_type), self, message)
self.event_emitter.emit(str(notify_type.MT_ALL), self, message) self.__msg_event_emitter.emit(str(notify_type.MT_ALL), self, message)
def wait_login(self, timeout=None): def wait_login(self, timeout=None):
log.info("wait login...") log.info("wait login...")
@ -479,13 +481,3 @@ class WeChat:
"remark": remark "remark": remark
} }
return self.__send_sync(send_type.MT_MODIFY_FRIEND_REMARK, data) return self.__send_sync(send_type.MT_MODIFY_FRIEND_REMARK, data)
def get_room_name(self, room_wxid: str) -> str:
"""
获取群名
"""
sql = f"select nickname from contact where username='{room_wxid}'"
result = self.sql_query(sql, 1)["result"]
if result:
return result[0][0]
return ''

View File

@ -8,7 +8,3 @@ class WeChatBindError(Exception):
class WeChatNotLoginError(Exception): class WeChatNotLoginError(Exception):
pass pass
class WeChatRuntimeError(Exception):
pass

View File

@ -1,7 +1,6 @@
import os import os
import sys import sys
import os.path import os.path
from ntchat.wc import SUPPORT_VERSIONS
def get_exec_dir(): def get_exec_dir():
@ -27,13 +26,9 @@ def get_helper_file(version):
return os.path.join(get_wc_dir(), f"helper_{version}.dat") return os.path.join(get_wc_dir(), f"helper_{version}.dat")
def has_helper_file(): def get_support_download_url():
for name in os.listdir(get_wc_dir()): return 'https://webcdn.m.qq.com/spcmgr/download/WeChat3.6.0.18.exe'
if name.startswith("helper_"):
return True
return False
def is_support_version(version): if __name__ == '__main__':
return version in SUPPORT_VERSIONS print(get_helper_file('3.6.0.18'))

View File

@ -1,3 +0,0 @@
SUPPORT_VERSIONS = [
'3.6.0.18'
]

View File

@ -3,7 +3,6 @@
%UserProfile%\.pyenv\pyenv-win\versions\3.8.0-win32\python.exe -m pip install --upgrade pip setuptools wheel %UserProfile%\.pyenv\pyenv-win\versions\3.8.0-win32\python.exe -m pip install --upgrade pip setuptools wheel
%UserProfile%\.pyenv\pyenv-win\versions\3.9.0-win32\python.exe -m pip install --upgrade pip setuptools wheel %UserProfile%\.pyenv\pyenv-win\versions\3.9.0-win32\python.exe -m pip install --upgrade pip setuptools wheel
%UserProfile%\.pyenv\pyenv-win\versions\3.10.0-win32\python.exe -m pip install --upgrade pip setuptools wheel %UserProfile%\.pyenv\pyenv-win\versions\3.10.0-win32\python.exe -m pip install --upgrade pip setuptools wheel
%UserProfile%\.pyenv\pyenv-win\versions\3.11.0-win32\python.exe -m pip install --upgrade pip setuptools wheel
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat" call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat"
pushd .. pushd ..
%UserProfile%\.pyenv\pyenv-win\versions\3.6.0-win32\python.exe setup.py bdist_wheel -d wheelhouse %UserProfile%\.pyenv\pyenv-win\versions\3.6.0-win32\python.exe setup.py bdist_wheel -d wheelhouse
@ -11,5 +10,4 @@ pushd ..
%UserProfile%\.pyenv\pyenv-win\versions\3.8.0-win32\python.exe setup.py bdist_wheel -d wheelhouse %UserProfile%\.pyenv\pyenv-win\versions\3.8.0-win32\python.exe setup.py bdist_wheel -d wheelhouse
%UserProfile%\.pyenv\pyenv-win\versions\3.9.0-win32\python.exe setup.py bdist_wheel -d wheelhouse %UserProfile%\.pyenv\pyenv-win\versions\3.9.0-win32\python.exe setup.py bdist_wheel -d wheelhouse
%UserProfile%\.pyenv\pyenv-win\versions\3.10.0-win32\python.exe setup.py bdist_wheel -d wheelhouse %UserProfile%\.pyenv\pyenv-win\versions\3.10.0-win32\python.exe setup.py bdist_wheel -d wheelhouse
%UserProfile%\.pyenv\pyenv-win\versions\3.11.0-win32\python.exe setup.py bdist_wheel -d wheelhouse
popd popd

View File

@ -3,7 +3,6 @@
%UserProfile%\.pyenv\pyenv-win\versions\3.8.0\python.exe -m pip install --upgrade pip setuptools wheel %UserProfile%\.pyenv\pyenv-win\versions\3.8.0\python.exe -m pip install --upgrade pip setuptools wheel
%UserProfile%\.pyenv\pyenv-win\versions\3.9.0\python.exe -m pip install --upgrade pip setuptools wheel %UserProfile%\.pyenv\pyenv-win\versions\3.9.0\python.exe -m pip install --upgrade pip setuptools wheel
%UserProfile%\.pyenv\pyenv-win\versions\3.10.0\python.exe -m pip install --upgrade pip setuptools wheel %UserProfile%\.pyenv\pyenv-win\versions\3.10.0\python.exe -m pip install --upgrade pip setuptools wheel
%UserProfile%\.pyenv\pyenv-win\versions\3.11.0\python.exe -m pip install --upgrade pip setuptools wheel
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
pushd .. pushd ..
%UserProfile%\.pyenv\pyenv-win\versions\3.6.0\python.exe setup.py bdist_wheel -d wheelhouse %UserProfile%\.pyenv\pyenv-win\versions\3.6.0\python.exe setup.py bdist_wheel -d wheelhouse
@ -11,5 +10,4 @@ pushd ..
%UserProfile%\.pyenv\pyenv-win\versions\3.8.0\python.exe setup.py bdist_wheel -d wheelhouse %UserProfile%\.pyenv\pyenv-win\versions\3.8.0\python.exe setup.py bdist_wheel -d wheelhouse
%UserProfile%\.pyenv\pyenv-win\versions\3.9.0\python.exe setup.py bdist_wheel -d wheelhouse %UserProfile%\.pyenv\pyenv-win\versions\3.9.0\python.exe setup.py bdist_wheel -d wheelhouse
%UserProfile%\.pyenv\pyenv-win\versions\3.10.0\python.exe setup.py bdist_wheel -d wheelhouse %UserProfile%\.pyenv\pyenv-win\versions\3.10.0\python.exe setup.py bdist_wheel -d wheelhouse
%UserProfile%\.pyenv\pyenv-win\versions\3.11.0\python.exe setup.py bdist_wheel -d wheelhouse
popd popd

View File

@ -194,7 +194,7 @@ extension.extra_compile_cpp_args = extra_compile_cpp_args[target_os]
setup( setup(
name='ntchat', name='ntchat',
version='0.1.17', version='0.1.15',
description='About Conversational RPA SDK for Chatbot Makers', description='About Conversational RPA SDK for Chatbot Makers',
long_description="", long_description="",
long_description_content_type='text/markdown', long_description_content_type='text/markdown',
@ -209,8 +209,7 @@ setup(
'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.10'
'Programming Language :: Python :: 3.11'
], ],
package_data={"": ["py.typed", "*.pyi", "helper*.dat"]}, package_data={"": ["py.typed", "*.pyi", "helper*.dat"]},
include_package_data=False, include_package_data=False,