mirror of
https://wget.la/https://github.com/Wxw-Gu/WechatExplorer
synced 2026-08-17 03:27:00 +08:00
207 lines
6.1 KiB
TypeScript
207 lines
6.1 KiB
TypeScript
import { Wcdb4Client, Wcdb4MessageQueryOptions } from './wcdb4-client'
|
|
|
|
export interface UserContact {
|
|
m_nsUsrName: string
|
|
nickname: string
|
|
avatar?: string
|
|
wechatNickname?: string
|
|
remark?: string
|
|
isFolded?: boolean
|
|
isMuted?: boolean
|
|
}
|
|
|
|
export interface WechatMessage {
|
|
mesLocalID: string
|
|
mesDes: number
|
|
messageType: string
|
|
msgCreateTime: string
|
|
msgContent: string
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
[key: string]: any
|
|
}
|
|
|
|
export interface Contact {
|
|
m_nsUsrName: string
|
|
m_nsNickName: string
|
|
md5: string
|
|
type: 'user' | 'group'
|
|
avatar?: string
|
|
}
|
|
|
|
export interface GroupMemberInfo {
|
|
m_nsUsrName: string
|
|
nickname: string
|
|
m_nsHeadImgUrl: string
|
|
}
|
|
|
|
export class WechatDb {
|
|
private wcdb4Client: Wcdb4Client
|
|
private chatMd5ToUsername = new Map<string, string>()
|
|
private chatTableMappingLoaded = false
|
|
|
|
static async create(rawKey: string, accountRoot?: string): Promise<WechatDb> {
|
|
const client = new Wcdb4Client(rawKey, accountRoot)
|
|
await client.openAsync()
|
|
return new WechatDb(rawKey, accountRoot, client)
|
|
}
|
|
|
|
constructor(
|
|
rawKey: string,
|
|
accountRoot?: string,
|
|
clientOverride?: Wcdb4Client,
|
|
initialChatTables?: { name: string; db_number: string }[]
|
|
) {
|
|
console.log(`Initializing WechatDb with key length: ${rawKey.trim().length}`)
|
|
const client = clientOverride || new Wcdb4Client(rawKey, accountRoot)
|
|
if (!clientOverride) client.open()
|
|
this.wcdb4Client = client
|
|
for (const table of initialChatTables || []) {
|
|
if (table.name.startsWith('Chat_')) {
|
|
this.chatMd5ToUsername.set(table.name.substring(5), table.db_number)
|
|
}
|
|
}
|
|
this.chatTableMappingLoaded = Boolean(initialChatTables)
|
|
}
|
|
|
|
private ensureChatTableMapping(): void {
|
|
if (this.chatTableMappingLoaded) return
|
|
for (const table of this.wcdb4Client.getChatTables()) {
|
|
if (table.name.startsWith('Chat_')) {
|
|
this.chatMd5ToUsername.set(table.name.substring(5), table.db_number)
|
|
}
|
|
}
|
|
this.chatTableMappingLoaded = true
|
|
}
|
|
|
|
public getUserList(nicknameFilter?: string): UserContact[] {
|
|
const keyword = (nicknameFilter || '').trim().toLowerCase()
|
|
return this.wcdb4Client
|
|
.getSessions()
|
|
.map((session) => ({
|
|
m_nsUsrName: session.username,
|
|
nickname: session.nickname || session.username,
|
|
avatar: session.avatar,
|
|
wechatNickname: session.wechatNickname,
|
|
remark: session.remark,
|
|
isFolded: session.isFolded,
|
|
isMuted: session.isMuted
|
|
}))
|
|
.filter((contact) => {
|
|
if (!keyword) return true
|
|
return (
|
|
contact.m_nsUsrName.toLowerCase().includes(keyword) ||
|
|
contact.nickname.toLowerCase().includes(keyword)
|
|
)
|
|
})
|
|
}
|
|
|
|
public getAllGroupContacts(): Record<string, string> {
|
|
const groupContacts: Record<string, string> = {}
|
|
for (const session of this.wcdb4Client.getSessions()) {
|
|
if (session.username.endsWith('@chatroom')) {
|
|
groupContacts[this.md5(session.username)] = session.nickname || session.username
|
|
}
|
|
}
|
|
return groupContacts
|
|
}
|
|
|
|
public getAllGroupMembers(): Record<string, string> {
|
|
const members: Record<string, string> = {}
|
|
for (const session of this.wcdb4Client.getSessions()) {
|
|
if (!session.username.endsWith('@chatroom')) continue
|
|
for (const member of this.wcdb4Client.getGroupMembers(session.username)) {
|
|
if (member.m_nsUsrName) {
|
|
members[member.m_nsUsrName] = member.nickname || member.m_nsUsrName
|
|
}
|
|
}
|
|
}
|
|
return members
|
|
}
|
|
|
|
public getGroupMembersForChat(userMd5: string): Record<string, string> {
|
|
this.ensureChatTableMapping()
|
|
const username = this.chatMd5ToUsername.get(userMd5)
|
|
if (!username || !username.endsWith('@chatroom')) return {}
|
|
|
|
const members: Record<string, string> = {}
|
|
for (const member of this.wcdb4Client.getGroupMembers(username)) {
|
|
if (member.m_nsUsrName) {
|
|
members[member.m_nsUsrName] = member.nickname || member.m_nsUsrName
|
|
}
|
|
}
|
|
return members
|
|
}
|
|
|
|
public getGroupMember(wxid: string, chatroomId?: string): GroupMemberInfo | null {
|
|
if (!chatroomId) return null
|
|
return (
|
|
this.wcdb4Client.getGroupMembers(chatroomId).find((member) => member.m_nsUsrName === wxid) ||
|
|
null
|
|
)
|
|
}
|
|
|
|
public getAllChatTables(): { name: string; db_number: string }[] {
|
|
return this.wcdb4Client.getChatTables()
|
|
}
|
|
|
|
public getMyAvatarUrl(): string | undefined {
|
|
return this.wcdb4Client.getMyAvatarUrl()
|
|
}
|
|
|
|
public getWcdb4Client(): Wcdb4Client {
|
|
return this.wcdb4Client
|
|
}
|
|
|
|
public close(): void {
|
|
this.wcdb4Client.close()
|
|
}
|
|
|
|
public closeAsync(timeoutMs?: number): Promise<boolean> {
|
|
return this.wcdb4Client.closeAsync(timeoutMs)
|
|
}
|
|
|
|
public getUserMessages(
|
|
userMd5: string,
|
|
startTime?: number,
|
|
endTime?: number,
|
|
options?: Wcdb4MessageQueryOptions
|
|
): WechatMessage[] {
|
|
this.ensureChatTableMapping()
|
|
const username = this.chatMd5ToUsername.get(userMd5)
|
|
if (!username) return []
|
|
return this.wcdb4Client.getMessages(username, startTime, endTime, options).map((message) => ({
|
|
...message,
|
|
...message.raw
|
|
}))
|
|
}
|
|
|
|
public async getUserMessagesAsync(
|
|
userMd5: string,
|
|
startTime?: number,
|
|
endTime?: number,
|
|
options?: Wcdb4MessageQueryOptions
|
|
): Promise<WechatMessage[]> {
|
|
this.ensureChatTableMapping()
|
|
const username = this.chatMd5ToUsername.get(userMd5)
|
|
if (!username) return []
|
|
const messages = await this.wcdb4Client.getMessagesAsync(username, startTime, endTime, options)
|
|
return messages.map((message) => ({ ...message, ...message.raw }))
|
|
}
|
|
|
|
public searchAllMessages(keyword: string): string | null {
|
|
const lowerKeyword = keyword.trim().toLowerCase()
|
|
if (!lowerKeyword) return null
|
|
for (const session of this.wcdb4Client.getSessions()) {
|
|
const found = this.wcdb4Client
|
|
.getMessages(session.username)
|
|
.some((message) => message.msgContent.toLowerCase().includes(lowerKeyword))
|
|
if (found) return `Chat_${this.md5(session.username)}`
|
|
}
|
|
return null
|
|
}
|
|
|
|
public md5(str: string): string {
|
|
return this.wcdb4Client.md5(str)
|
|
}
|
|
}
|