From 9e2f305921f3e905b2096918d593a05627bfcc37 Mon Sep 17 00:00:00 2001 From: LVtomatoJ Date: Sun, 4 Feb 2024 11:28:30 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E5=8D=95api?= =?UTF-8?q?=E7=9A=84=E8=BF=90=E8=A1=8C=E5=92=8C=E8=BF=94=E5=9B=9E=E8=81=8A?= =?UTF-8?q?=E5=A4=A9=E4=B8=AD=E6=89=80=E6=9C=89=E7=94=A8=E6=88=B7=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=20(#73)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add msg only api、add 单api运行方式、增加返回会话所有用户信息接口 --- pywxdump/analyzer/export_chat.py | 65 ++++++++++++++++++++++++++++++++ pywxdump/api/api.py | 40 ++++++++++++++++++++ pywxdump/cli.py | 27 ++++++++++++- 3 files changed, 131 insertions(+), 1 deletion(-) diff --git a/pywxdump/analyzer/export_chat.py b/pywxdump/analyzer/export_chat.py index a997dee..fae3222 100644 --- a/pywxdump/analyzer/export_chat.py +++ b/pywxdump/analyzer/export_chat.py @@ -24,6 +24,30 @@ from .utils import get_md5, attach_databases, execute_sql, get_type_name, match_ from .db_parsing import parse_xml_string, decompress_CompressContent, read_BytesExtra +def get_contact(MicroMsg_db_path,wx_id): + """ + 获取联系人信息 + :param MicroMsg_db_path: MicroMsg.db 文件路径 + :param wx_id: 微信id + :return: 联系人信息 + """ + db = sqlite3.connect(MicroMsg_db_path) + cursor = db.cursor() + # 获取username是wx_id的用户 + sql = ("SELECT A.UserName, A.NickName, A.Remark,A.Alias,A.Reserved6,B.bigHeadImgUrl " + "FROM Contact A,ContactHeadImgUrl B " + f"WHERE A.UserName = '{wx_id}' AND A.UserName = B.usrName " + "ORDER BY NickName ASC;") + cursor.execute(sql) + result = cursor.fetchone() + print('联系人信息:', result) + if not result: + print('居然没找到!') + print(wx_id) + return None + return {"username": result[0], "nickname": result[1], "remark": result[2], "account": result[3], "describe": result[4], "headImgUrl": result[5]} + + def get_contact_list(MicroMsg_db_path): """ 获取联系人列表 @@ -79,6 +103,47 @@ def get_chatroom_list(MicroMsg_db_path): "Announcement": Announcement, "AnnouncementEditor": AnnouncementEditor}) return rooms +def get_room_user_list(MSG_db_path, selected_talker): + """ + 获取群聊中包含的所有用户列表 + :param MSG_db_path: MSG.db 文件路径 + :param selected_talker: 选中的聊天对象 wxid + :return: 聊天用户列表 + """ + + # 连接 MSG_ALL.db 数据库,并执行查询 + db1 = sqlite3.connect(MSG_db_path) + cursor1 = db1.cursor() + + sql = ( + "SELECT localId, IsSender, StrContent, StrTalker, Sequence, Type, SubType,CreateTime,MsgSvrID,DisplayContent,CompressContent,BytesExtra,ROW_NUMBER() OVER (ORDER BY CreateTime ASC) AS id " + "FROM MSG WHERE StrTalker=? " + "ORDER BY CreateTime ASC") + + cursor1.execute(sql, (selected_talker,)) + result1 = cursor1.fetchall() + cursor1.close() + db1.close() + user_list = [] + read_user_wx_id = [] + for row in result1: + localId, IsSender, StrContent, StrTalker, Sequence, Type, SubType, CreateTime, MsgSvrID, DisplayContent, CompressContent, BytesExtra, id = row + bytes_extra = read_BytesExtra(BytesExtra) + if bytes_extra: + try: + talker = bytes_extra['3'][0]['2'].decode('utf-8', errors='ignore') + except: + continue + if talker in read_user_wx_id: + continue + user = get_contact(MSG_db_path, talker) + if not user: + continue + user_list.append(user) + read_user_wx_id.append(talker) + return user_list + + def get_msg_list(MSG_db_path, selected_talker="", start_index=0, page_size=500): """ diff --git a/pywxdump/api/api.py b/pywxdump/api/api.py index c50928b..ad6b10e 100644 --- a/pywxdump/api/api.py +++ b/pywxdump/api/api.py @@ -13,6 +13,7 @@ import shutil from flask import Flask, request, render_template, g, Blueprint, send_file, make_response, session from pywxdump import analyzer, read_img_dat, read_audio, get_wechat_db, get_core_db +from pywxdump.analyzer.export_chat import get_contact, get_room_user_list from pywxdump.api.rjson import ReJson, RqJson from pywxdump.api.utils import read_session, save_session, error9999 from pywxdump import read_info, VERSION_LIST, batch_decrypt, BiasAddr, merge_db, decrypt_merge @@ -190,6 +191,45 @@ def contact_count_list(): except Exception as e: return ReJson(9999, msg=str(e)) +@api.route('/api/msgs_user_list',methods=['GET','POST']) +@error9999 +def get_msg_user_list(): + msg_path = request.headers.get("msg_path") + micro_path = request.headers.get("micro_path") + if not msg_path: + msg_path = read_session(g.sf, "msg_path") + if not micro_path: + micro_path = read_session(g.sf, "micro_path") + wxid = request.json.get("wxid") + # msg_list = analyzer.get_msg_list(msg_path, wxid, start_index=start, page_size=limit) + my_wxid = read_session(g.sf, "my_wxid") + userlist = [] + if wxid.endswith("@chatroom"): + # 群聊 + userlist = get_room_user_list(msg_path, wxid) + else: + # 单聊 + user = get_contact(micro_path, wxid) + my_user = get_contact(micro_path,my_wxid) + userlist.append(user) + userlist.append(my_user) + return ReJson(0, {"user_list":userlist}) + +@api.route('/api/msgs_list',methods=['GET','POST']) +@error9999 +def get_msg_list(): + msg_path = request.headers.get("msg_path") + micro_path = request.headers.get("micro_path") + if not msg_path: + msg_path = read_session(g.sf, "msg_path") + if not micro_path: + micro_path = read_session(g.sf, "micro_path") + start = request.json.get("start") + limit = request.json.get("limit") + wxid = request.json.get("wxid") + my_wxid = read_session(g.sf, "my_wxid") + msg_list = analyzer.get_msg_list(msg_path, wxid, start_index=start, page_size=limit) + return ReJson(0, {"msg_list":msg_list,'my_wxid':my_wxid}) @api.route('/api/msgs', methods=["GET", 'POST']) @error9999 diff --git a/pywxdump/cli.py b/pywxdump/cli.py index 93c5e3d..6ca12f4 100644 --- a/pywxdump/cli.py +++ b/pywxdump/cli.py @@ -412,6 +412,26 @@ class MainUi(): start_falsk(port=port, online=online, debug=debug) +class MainApi(): + def init_parses(self, parser): + self.mode = "api" + # 添加 'api' 子命令解析器 + sb_api = parser.add_parser(self.mode, help="启动api") + sb_api.add_argument("-p", '--port', metavar="", type=int, help="(可选)端口号", default=5000) + sb_api.add_argument("--online", type=bool, help="(可选)是否在线查看(局域网查看)", required=False, default=False, + metavar="") + sb_api.add_argument("--debug", type=bool, help="(可选)是否开启debug模式", default=False) + return sb_api + + def run(self, args): + print(f"[*] PyWxDump v{pywxdump.__version__}") + # 从命令行参数获取值 + online = args.online + port = args.port + debug = args.debug + + start_falsk(port=port, online=online, debug=debug,isopenBrowser=False) + class CustomArgumentParser(argparse.ArgumentParser): def format_help(self): @@ -487,11 +507,16 @@ def console_run(): sb_ui = main_ui.init_parses(subparsers) modes[main_ui.mode] = main_ui + # 添加 'api' 子命令解析器 + main_api = MainApi() + sb_api = main_api.init_parses(subparsers) + modes[main_api.mode] = main_api + # 检查是否需要显示帮助信息 if len(sys.argv) == 1: sys.argv.append('ui') elif len(sys.argv) == 2 and sys.argv[1] in modes.keys() and sys.argv[1] not in [main_all.mode, main_wx_info.mode, - main_wx_db_path.mode, main_ui.mode]: + main_wx_db_path.mode, main_ui.mode ,main_api.mode]: sys.argv.append('-h') args = parser.parse_args() # 解析命令行参数