适配微信4.0.3正式版,修复media.db不存在的问题,修复图片、视频、文件路径异常的问题

This commit is contained in:
SiYuan
2025-04-03 13:18:13 +08:00
parent 6dde500e07
commit e4a39135c2
13 changed files with 471 additions and 389 deletions

View File

@@ -9,6 +9,7 @@
@Description :
"""
import os
import shutil
import subprocess
import sys
import traceback
@@ -35,6 +36,8 @@ class MediaDB(DataBaseBase):
from VoiceInfo
where svr_id = ?
'''
if not self.DB:
return b''
for db in self.DB:
cursor = db.cursor()
cursor.execute(sql, [server_id])
@@ -100,16 +103,19 @@ class MediaDB(DataBaseBase):
if not (os.path.exists(db_path) or os.path.isfile(db_path)):
print(f'{db_path} 不存在')
return
for db in self.DB:
cursor = db.cursor()
try:
# 获取列名
increase_data(db_path, cursor, db, 'VoiceInfo', 'svr_id')
increase_data(db_path, cursor, db, 'Name2Id', 'user_name')
increase_update_data(db_path, cursor, db, 'Timestamp', 'timestamp')
except:
print(f"数据库操作错误: {traceback.format_exc()}")
db.rollback()
if not self.DB:
shutil.copy(db_path,os.path.join(self.db_dir,self.db_file_name))
else:
for db in self.DB:
cursor = db.cursor()
try:
# 获取列名
increase_data(db_path, cursor, db, 'VoiceInfo', 'svr_id')
increase_data(db_path, cursor, db, 'Name2Id', 'user_name')
increase_update_data(db_path, cursor, db, 'Timestamp', 'timestamp')
except:
print(f"数据库操作错误: {traceback.format_exc()}")
db.rollback()
if __name__ == '__main__':

View File

@@ -309,7 +309,7 @@ order by sort_seq
task_(db_path, cursor, db)
tasks.append([db_path, cursor, db])
else:
shutil.copy(db_path, os.path.join(self.db_dir, 'Multi', file_name))
shutil.copy(db_path, os.path.join(self.db_dir, 'message', file_name))
# print(tasks)
# 使用线程池 (没有加快合并速度)
# with ThreadPoolExecutor(max_workers=len(tasks)) as executor:

View File

@@ -430,11 +430,6 @@ def get_nickname(pid):
for string in match.strings:
instance = string.instances[0]
offset, content = instance.offset, instance.matched_data
# print(
# f"匹配字符串: {identifier} 内容: 偏移: {offset} 在地址: {hex(base_address + offset + 0x10)}")
# print(string)
with open('a.bin','wb') as f:
f.write(target_data)
phone_addr = offset + 0x10
phone = read_string(target_data, phone_addr, 11)

View File

@@ -210,7 +210,8 @@ class DataBaseV3(DataBaseInterface):
flag &= self.open_media_db.init_database(db_dir)
flag &= self.open_msg_db.init_database(db_dir)
flag &= self.audio2text_db.init_database(db_dir)
self.audio2text_db.create() # 初始化数据转文字数据库
if flag:
self.audio2text_db.create() # 初始化语音转文字数据库
return flag
# self.sns_db.init_database(db_dir)

View File

@@ -96,11 +96,12 @@ class DataBaseV4(DataBaseInterface):
flag &= self.session_db.init_database(db_dir)
flag &= self.message_db.init_database(db_dir)
flag &= self.biz_message_db.init_database(db_dir)
flag &= self.media_db.init_database(db_dir)
self.media_db.init_database(db_dir)
flag &= self.hardlink_db.init_database(db_dir)
flag &= self.emotion_db.init_database(db_dir)
flag &= self.audio2text_db.init_database(db_dir)
self.audio2text_db.create() # 初始化数据转文字数据库
if flag:
self.audio2text_db.create() # 初始化语音转文字数据库
return flag
def close(self):

View File

@@ -24,12 +24,14 @@ class DataBaseBase:
def init_database(self, db_dir=''):
self.db_dir = db_dir
if not os.path.exists(db_dir):
return False
db_path = os.path.join(db_dir, self.db_file_name)
if not os.path.exists(db_path) and self.db_file_name != 'Audio2Text.db':
return False
db_file_name = self.db_file_name
self.db_file_name = []
if self.is_series:
self.db_file_name = []
self.DB = []
self.cursor = []
for i in range(100):

View File

@@ -57,6 +57,7 @@ def parser_emoji(xml_content):
}
except:
logger.error(traceback.format_exc())
logger.error(xml_content)
finally:
return result

View File

@@ -4,10 +4,35 @@ message PackedInfoDataImg2 {
int32 field1 = 1;
int32 field2 = 2;
ImageInfo imageInfo = 3;
VideoInfo videoInfo = 4;
FileInfo fileInfo = 7;
}
message ImageInfo {
int32 height = 1;
int32 width = 2;
string filename = 4;
}
message VideoInfo {
int32 height = 4;
int32 width = 5;
string filename = 8;
}
message FileInfo {
FileSubMessage1 fileInfo = 1;
FileSubMessage2 field2 = 2;
string field3 = 3;
}
message FileSubMessage1 {
int32 field1 = 1;
string filename = 2;
}
message FileSubMessage2 {
string field1 = 1;
string field2 = 2;
string field3 = 3;
}

View File

@@ -13,15 +13,23 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1bpacked_info_data_img2.proto\"S\n\x12PackedInfoDataImg2\x12\x0e\n\x06\x66ield1\x18\x01 \x01(\x05\x12\x0e\n\x06\x66ield2\x18\x02 \x01(\x05\x12\x1d\n\timageInfo\x18\x03 \x01(\x0b\x32\n.ImageInfo\"<\n\tImageInfo\x12\x0e\n\x06height\x18\x01 \x01(\x05\x12\r\n\x05width\x18\x02 \x01(\x05\x12\x10\n\x08\x66ilename\x18\x04 \x01(\tb\x06proto3')
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1bpacked_info_data_img2.proto\"\x8f\x01\n\x12PackedInfoDataImg2\x12\x0e\n\x06\x66ield1\x18\x01 \x01(\x05\x12\x0e\n\x06\x66ield2\x18\x02 \x01(\x05\x12\x1d\n\timageInfo\x18\x03 \x01(\x0b\x32\n.ImageInfo\x12\x1d\n\tvideoInfo\x18\x04 \x01(\x0b\x32\n.VideoInfo\x12\x1b\n\x08\x66ileInfo\x18\x07 \x01(\x0b\x32\t.FileInfo\"<\n\tImageInfo\x12\x0e\n\x06height\x18\x01 \x01(\x05\x12\r\n\x05width\x18\x02 \x01(\x05\x12\x10\n\x08\x66ilename\x18\x04 \x01(\t\"<\n\tVideoInfo\x12\x0e\n\x06height\x18\x04 \x01(\x05\x12\r\n\x05width\x18\x05 \x01(\x05\x12\x10\n\x08\x66ilename\x18\x08 \x01(\t\"`\n\x08\x46ileInfo\x12\"\n\x08\x66ileInfo\x18\x01 \x01(\x0b\x32\x10.FileSubMessage1\x12 \n\x06\x66ield2\x18\x02 \x01(\x0b\x32\x10.FileSubMessage2\x12\x0e\n\x06\x66ield3\x18\x03 \x01(\t\"3\n\x0f\x46ileSubMessage1\x12\x0e\n\x06\x66ield1\x18\x01 \x01(\x05\x12\x10\n\x08\x66ilename\x18\x02 \x01(\t\"A\n\x0f\x46ileSubMessage2\x12\x0e\n\x06\x66ield1\x18\x01 \x01(\t\x12\x0e\n\x06\x66ield2\x18\x02 \x01(\t\x12\x0e\n\x06\x66ield3\x18\x03 \x01(\tb\x06proto3')
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'packed_info_data_img2_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
_PACKEDINFODATAIMG2._serialized_start=31
_PACKEDINFODATAIMG2._serialized_end=114
_IMAGEINFO._serialized_start=116
_IMAGEINFO._serialized_end=176
_PACKEDINFODATAIMG2._serialized_start=32
_PACKEDINFODATAIMG2._serialized_end=175
_IMAGEINFO._serialized_start=177
_IMAGEINFO._serialized_end=237
_VIDEOINFO._serialized_start=239
_VIDEOINFO._serialized_end=299
_FILEINFO._serialized_start=301
_FILEINFO._serialized_end=397
_FILESUBMESSAGE1._serialized_start=399
_FILESUBMESSAGE1._serialized_end=450
_FILESUBMESSAGE2._serialized_start=452
_FILESUBMESSAGE2._serialized_end=517
# @@protoc_insertion_point(module_scope)

View File

@@ -3,19 +3,19 @@ syntax = "proto3";
message PackedInfoData {
int32 field1 = 1;
int32 field2 = 2;
NestedMessage field7 = 7;
FileInfo fileInfo = 7;
AnotherNestedMessage info = 9;
}
message NestedMessage {
SubMessage1 field1 = 1;
message FileInfo {
SubMessage1 fileInfo = 1;
SubMessage2 field2 = 2;
string field3 = 3;
}
message SubMessage1 {
int32 field1 = 1;
string field2 = 2;
string filename = 2;
}
message SubMessage2 {

View File

@@ -42,9 +42,12 @@ source,message_content,compress_content"
def decompress(data):
dctx = zstd.ZstdDecompressor() # 创建解压对象
x = dctx.decompress(data).strip(b'\x00').strip()
return x.decode('utf-8').strip()
try:
dctx = zstd.ZstdDecompressor() # 创建解压对象
x = dctx.decompress(data).strip(b'\x00').strip()
return x.decode('utf-8').strip()
except:
return ''
class LimitedDict:
@@ -255,8 +258,8 @@ class ImageMessageFactory(MessageFactory, Singleton):
# 转换为 JSON 格式
packed_info_data = MessageToDict(packed_info_data_proto)
image_info = packed_info_data.get('imageInfo', {})
width = image_info.get('width',0)
height = image_info.get('height',0)
width = image_info.get('width', 0)
height = image_info.get('height', 0)
filename = image_info.get('filename', '').strip().strip('"').strip()
except:
pass
@@ -344,6 +347,19 @@ class AudioMessageFactory(MessageFactory, Singleton):
class VideoMessageFactory(MessageFactory, Singleton):
def create(self, message, username, manager):
is_sender, wxid, message_content = self.common_attribute(message, username, manager)
filename = ''
try:
# 2025年3月微信4.0.3正式版修改了img命名方式才有了这个东西
packed_info_data_proto = packed_info_data_img2_pb2.PackedInfoDataImg2()
packed_info_data_proto.ParseFromString(message[14])
# 转换为 JSON 格式
packed_info_data = MessageToDict(packed_info_data_proto)
image_info = packed_info_data.get('videoInfo', {})
width = image_info.get('width', 0)
height = image_info.get('height', 0)
filename = image_info.get('filename', '').strip().strip('"').strip()
except:
pass
msg = VideoMessage(
local_id=message[0],
server_id=message[1],
@@ -361,7 +377,7 @@ class VideoMessageFactory(MessageFactory, Singleton):
md5='',
path='',
file_size=0,
file_name='',
file_name=filename,
file_type='mp4',
thumb_path='',
duration=0,
@@ -372,12 +388,25 @@ class VideoMessageFactory(MessageFactory, Singleton):
msg.file_size = video_dic.get('size', 0)
msg.md5 = video_dic.get('md5', '')
msg.raw_md5 = video_dic.get('rawmd5', '')
msg.path = manager.hardlink_db.get_video(msg.raw_md5, False)
msg.thumb_path = manager.hardlink_db.get_video(msg.raw_md5, True)
if not msg.path:
msg.path = manager.hardlink_db.get_video(msg.md5, False)
msg.thumb_path = manager.hardlink_db.get_video(msg.md5, True)
# logger.error(f'{msg.path} {msg.thumb_path}')
month = msg.str_time[:7] # 2025-01
if filename:
# 微信4.0.3正式版增加
video_dir = os.path.join('msg', 'video', month)
video_path = os.path.join(video_dir, f'{filename}_raw.mp4')
if os.path.exists(os.path.join(Me().wx_dir, video_path)):
msg.path = video_path
msg.thumb_path = os.path.join(video_dir, f'{filename}.jpg')
else:
msg.path = os.path.join(video_dir, f'{filename}.mp4')
msg.thumb_path = os.path.join(video_dir, f'{filename}.jpg')
else:
msg.path = manager.hardlink_db.get_video(msg.raw_md5, False)
msg.thumb_path = manager.hardlink_db.get_video(msg.raw_md5, True)
if not msg.path:
msg.path = manager.hardlink_db.get_video(msg.md5, False)
msg.thumb_path = manager.hardlink_db.get_video(msg.md5, True)
# logger.error(f'{msg.path} {msg.thumb_path}')
self.add_message(msg)
return msg
@@ -847,7 +876,19 @@ class FileMessageFactory(MessageFactory, Singleton):
is_sender, wxid, message_content = self.common_attribute(message, username, manager)
info = parser_file(message_content)
md5 = info.get('md5', '')
file_path = manager.get_file(md5)
filename = info.get('filename','')
if not filename:
try:
# 2025年3月微信4.0.3正式版修改了img命名方式才有了这个东西
packed_info_data_proto = packed_info_data_img2_pb2.PackedInfoDataImg2()
packed_info_data_proto.ParseFromString(message[14])
# 转换为 JSON 格式
packed_info_data = MessageToDict(packed_info_data_proto)
image_info = packed_info_data.get('fileInfo', {})
file_info = image_info.get('fileInfo', {})
filename = file_info.get('filename', '').strip()
except:
pass
msg = FileMessage(
local_id=message[0],
server_id=message[1],
@@ -862,12 +903,21 @@ class FileMessageFactory(MessageFactory, Singleton):
avatar_src=self.contacts[wxid].small_head_img_url,
status=message[7],
xml_content=message_content,
path=file_path,
path='',
md5=md5,
file_type=info.get('file_type', ''),
file_name=info.get('file_name', ''),
file_size=info.get('file_size', 0)
)
# file_path = manager.get_file(md5)
if filename:
month = msg.str_time[:7] # 2025-01
# 微信4.0.3正式版增加
video_dir = os.path.join('msg', 'file', month)
file_path = os.path.join(video_dir, f'{filename}')
msg.path = file_path
else:
msg.path = manager.get_file(md5)
self.add_message(msg)
return msg