2024-05-18 00:23:59 +08:00
|
|
|
|
# -*- coding: utf-8 -*-#
|
|
|
|
|
# -------------------------------------------------------------------------------
|
2024-08-13 17:31:06 +08:00
|
|
|
|
# Name: Favorite.py
|
|
|
|
|
# Description: 负责处理wx收藏数据库
|
2024-05-18 00:23:59 +08:00
|
|
|
|
# Author: xaoyaoo
|
|
|
|
|
# Date: 2024/05/18
|
|
|
|
|
# -------------------------------------------------------------------------------
|
2024-10-09 14:40:50 +08:00
|
|
|
|
from collections import defaultdict
|
|
|
|
|
|
2024-05-18 00:23:59 +08:00
|
|
|
|
from .dbbase import DatabaseBase
|
2024-05-18 22:23:54 +08:00
|
|
|
|
from .utils import timestamp2str, xml2dict
|
|
|
|
|
|
2024-05-18 00:23:59 +08:00
|
|
|
|
|
2024-05-18 00:26:53 +08:00
|
|
|
|
# * FavItems:收藏的消息条目列表
|
|
|
|
|
# * FavDataItem:收藏的具体数据。大概可以确定以下两点
|
|
|
|
|
# * 即使只是简单收藏一篇公众号文章也会在 FavDataItem 中有一个对应的记录
|
|
|
|
|
# * 对于收藏的合并转发类型的消息,合并转发中的每一条消息在 FavDataItem 中都是一个独立的记录
|
|
|
|
|
# * FavTags:为收藏内容添加的标签
|
2024-05-18 00:23:59 +08:00
|
|
|
|
|
2024-05-18 22:23:54 +08:00
|
|
|
|
|
2024-08-03 00:21:16 +08:00
|
|
|
|
class FavoriteHandler(DatabaseBase):
|
2024-05-18 00:23:59 +08:00
|
|
|
|
_class_name = "Favorite"
|
2024-08-03 00:21:16 +08:00
|
|
|
|
Favorite_required_tables = ["FavItems", "FavDataItem", "FavTagDatas", "FavBindTagDatas"]
|
2024-05-18 00:23:59 +08:00
|
|
|
|
|
2024-05-19 21:06:46 +08:00
|
|
|
|
def get_tags(self, LocalID):
|
2024-05-18 22:23:54 +08:00
|
|
|
|
"""
|
|
|
|
|
return: {LocalID: TagName}
|
|
|
|
|
"""
|
2024-08-13 12:53:53 +08:00
|
|
|
|
if not self.tables_exist("FavTagDatas"):
|
|
|
|
|
return {}
|
2024-05-19 21:06:46 +08:00
|
|
|
|
if LocalID is None:
|
|
|
|
|
sql = "select LocalID, TagName from FavTagDatas order by ServerSeq"
|
|
|
|
|
else:
|
|
|
|
|
sql = "select LocalID, TagName from FavTagDatas where LocalID = '%s' order by ServerSeq " % LocalID
|
2024-08-03 00:21:16 +08:00
|
|
|
|
tags = self.execute(sql) # [(1, 797940830, '程序语言类'), (2, 806153863, '账单')]
|
2024-05-18 22:23:54 +08:00
|
|
|
|
# 转换为字典
|
|
|
|
|
tags = {tag[0]: tag[1] for tag in tags}
|
|
|
|
|
return tags
|
|
|
|
|
|
|
|
|
|
def get_FavBindTags(self):
|
|
|
|
|
"""
|
|
|
|
|
return: [(FavLocalID, TagName)]
|
|
|
|
|
"""
|
|
|
|
|
sql = "select A.FavLocalID, B.TagName from FavBindTagDatas A, FavTagDatas B where A.TagLocalID = B.LocalID"
|
2024-08-03 00:21:16 +08:00
|
|
|
|
FavBindTags = self.execute(sql)
|
2024-05-18 22:23:54 +08:00
|
|
|
|
return FavBindTags
|
|
|
|
|
|
2024-05-18 00:23:59 +08:00
|
|
|
|
def get_favorite(self):
|
2024-05-18 22:23:54 +08:00
|
|
|
|
"""
|
|
|
|
|
return: [{FavItemsFields}, {FavItemsFields}]
|
|
|
|
|
"""
|
|
|
|
|
FavItemsFields = {
|
|
|
|
|
"FavLocalID": "本地收藏ID",
|
|
|
|
|
"SvrFavId": "服务器收藏ID",
|
|
|
|
|
"SourceId": "源ID",
|
|
|
|
|
"Type": "类型",
|
|
|
|
|
"SourceType": "源类型",
|
|
|
|
|
"LocalStatus": "本地状态",
|
|
|
|
|
"Flag": "标记",
|
|
|
|
|
"Status": "状态",
|
|
|
|
|
"FromUser": "源用户",
|
|
|
|
|
"RealChatName": "实际聊天名称",
|
|
|
|
|
"SearchKey": "搜索关键字",
|
|
|
|
|
"UpdateTime": "更新时间",
|
|
|
|
|
"reseverd0": "预留字段0",
|
|
|
|
|
"XmlBuf": "XML缓冲区"
|
|
|
|
|
}
|
|
|
|
|
FavDataItemFields = {
|
|
|
|
|
"FavLocalID": "本地收藏ID",
|
|
|
|
|
"Type": "类型",
|
|
|
|
|
"DataId": "数据ID",
|
|
|
|
|
"HtmlId": "HTML ID",
|
|
|
|
|
"Datasourceid": "数据源ID",
|
|
|
|
|
"Datastatus": "数据状态",
|
|
|
|
|
"Datafmt": "数据格式",
|
|
|
|
|
"Datatitle": "数据标题",
|
|
|
|
|
"Datadesc": "数据描述",
|
|
|
|
|
"Thumbfullmd5": "缩略图全MD5",
|
|
|
|
|
"Thumbhead256md5": "缩略图头256MD5",
|
|
|
|
|
"Thumbfullsize": "缩略图全尺寸",
|
|
|
|
|
"fullmd5": "全MD5",
|
|
|
|
|
"head256md5": "头256MD5",
|
|
|
|
|
"fullsize": "全尺寸",
|
|
|
|
|
"cdn_thumburl": "CDN缩略图URL",
|
|
|
|
|
"cdn_thumbkey": "CDN缩略图KEY",
|
|
|
|
|
"thumb_width": "缩略图宽度",
|
|
|
|
|
"thumb_height": "缩略图高度",
|
|
|
|
|
"cdn_dataurl": "CDN数据URL",
|
|
|
|
|
"cdn_datakey": "CDN数据KEY",
|
|
|
|
|
"cdn_encryver": "CDN加密版本",
|
|
|
|
|
"duration": "时长",
|
|
|
|
|
"stream_weburl": "流媒体WEB URL",
|
|
|
|
|
"stream_dataurl": "流媒体数据URL",
|
|
|
|
|
"stream_lowbandurl": "流媒体低带宽URL",
|
|
|
|
|
"sourcethumbpath": "源缩略图路径",
|
|
|
|
|
"sourcedatapath": "源数据路径",
|
|
|
|
|
"stream_videoid": "流媒体视频ID",
|
|
|
|
|
"Rerserved1": "保留字段1",
|
|
|
|
|
"Rerserved2": "保留字段2",
|
|
|
|
|
"Rerserved3": "保留字段3",
|
|
|
|
|
"Rerserved4": "保留字段4",
|
|
|
|
|
"Rerserved5": "保留字段5",
|
|
|
|
|
"Rerserved6": "保留字段6",
|
|
|
|
|
"Rerserved7": "保留字段7"
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-13 12:53:53 +08:00
|
|
|
|
if not self.tables_exist(["FavItems", "FavDataItem"]):
|
|
|
|
|
return False
|
|
|
|
|
|
2024-05-18 22:23:54 +08:00
|
|
|
|
sql1 = "select " + ",".join(FavItemsFields.keys()) + " from FavItems order by UpdateTime desc"
|
|
|
|
|
sql2 = "select " + ",".join(FavDataItemFields.keys()) + " from FavDataItem B order by B.RecId asc"
|
|
|
|
|
|
2024-08-03 00:21:16 +08:00
|
|
|
|
FavItemsList = self.execute(sql1)
|
|
|
|
|
FavDataItemList = self.execute(sql2)
|
2024-05-18 22:23:54 +08:00
|
|
|
|
if FavItemsList is None or len(FavItemsList) == 0:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
FavDataDict = {}
|
|
|
|
|
if FavDataItemList and len(FavDataItemList) >= 0:
|
|
|
|
|
for item in FavDataItemList:
|
|
|
|
|
data_dict = {}
|
|
|
|
|
for i, key in enumerate(FavDataItemFields.keys()):
|
|
|
|
|
data_dict[key] = item[i]
|
|
|
|
|
FavDataDict[item[0]] = FavDataDict.get(item[0], []) + [data_dict]
|
|
|
|
|
# 获取标签
|
|
|
|
|
FavTags = self.get_FavBindTags()
|
|
|
|
|
FavTagsDict = {}
|
|
|
|
|
for FavLocalID, TagName in FavTags:
|
|
|
|
|
FavTagsDict[FavLocalID] = FavTagsDict.get(FavLocalID, []) + [TagName]
|
2024-08-18 13:33:08 +08:00
|
|
|
|
try:
|
|
|
|
|
import pandas as pd
|
|
|
|
|
except ImportError:
|
|
|
|
|
return False
|
2024-05-18 22:23:54 +08:00
|
|
|
|
pf = pd.DataFrame(FavItemsList)
|
|
|
|
|
pf.columns = FavItemsFields.keys() # set column names
|
|
|
|
|
pf["UpdateTime"] = pf["UpdateTime"].apply(timestamp2str) # 处理时间
|
|
|
|
|
pf["XmlBuf"] = pf["XmlBuf"].apply(xml2dict) # 处理xml
|
2024-10-09 14:40:50 +08:00
|
|
|
|
pf["TypeName"] = pf["Type"].apply(Favorite_type_converter) # 添加类型名称列
|
2024-05-18 22:23:54 +08:00
|
|
|
|
pf["FavData"] = pf["FavLocalID"].apply(lambda x: FavDataDict.get(x, [])) # 添加数据列
|
|
|
|
|
pf["Tags"] = pf["FavLocalID"].apply(lambda x: FavTagsDict.get(x, [])) # 添加标签列
|
|
|
|
|
pf = pf.fillna("") # 去掉Nan
|
|
|
|
|
rdata = pf.to_dict(orient="records")
|
|
|
|
|
return rdata
|
2024-08-03 00:21:16 +08:00
|
|
|
|
|
|
|
|
|
|
2024-10-09 14:40:50 +08:00
|
|
|
|
def Favorite_type_converter(type_id_or_name: [str, int]):
|
|
|
|
|
"""
|
|
|
|
|
收藏类型ID与名称转换
|
|
|
|
|
名称(str)=>ID(int)
|
|
|
|
|
ID(int)=>名称(str)
|
|
|
|
|
:param type_id_or_name: 消息类型ID或名称
|
|
|
|
|
:return: 消息类型名称或ID
|
|
|
|
|
"""
|
|
|
|
|
type_name_dict = defaultdict(lambda: "未知", {
|
2024-08-03 00:21:16 +08:00
|
|
|
|
1: "文本", # 文本 已测试
|
|
|
|
|
2: "图片", # 图片 已测试
|
|
|
|
|
3: "语音", # 语音
|
|
|
|
|
4: "视频", # 视频 已测试
|
|
|
|
|
5: "链接", # 链接 已测试
|
|
|
|
|
6: "位置", # 位置
|
|
|
|
|
7: "小程序", # 小程序
|
|
|
|
|
8: "文件", # 文件 已测试
|
|
|
|
|
14: "聊天记录", # 聊天记录 已测试
|
|
|
|
|
16: "群聊视频", # 群聊中的视频 可能
|
|
|
|
|
18: "笔记" # 笔记 已测试
|
2024-10-09 14:40:50 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if isinstance(type_id_or_name, int):
|
|
|
|
|
return type_name_dict[type_id_or_name]
|
|
|
|
|
elif isinstance(type_id_or_name, str):
|
|
|
|
|
return next((k for k, v in type_name_dict.items() if v == type_id_or_name), (0, 0))
|
|
|
|
|
else:
|
|
|
|
|
raise ValueError("Invalid input type")
|