Compare commits

..

17 Commits

Author SHA1 Message Date
idranme
67d3dfb3cf Merge pull request #367 from LLOneBot/dev
3.30.5
2024-08-25 23:09:44 +08:00
idranme
afe8392a1e chore: v3.30.5 2024-08-25 23:07:33 +08:00
idranme
c1f5c5cd58 fix 2024-08-25 20:00:13 +08:00
idranme
85001a40da Merge pull request #366 from LLOneBot/dev
3.30.4
2024-08-23 17:05:03 +08:00
idranme
867a05c85a chore: v3.30.4 2024-08-23 17:03:58 +08:00
idranme
d8a63f6561 fix 2024-08-23 17:02:31 +08:00
idranme
e9fb9d1b30 Update publish.yml 2024-08-23 16:08:59 +08:00
idranme
b4fc987537 Merge pull request #365 from LLOneBot/dev
3.30.3
2024-08-23 13:40:59 +08:00
idranme
d0ccf53d88 chore: v3.30.3 2024-08-23 13:39:26 +08:00
idranme
d5ca94569d fix 2024-08-23 13:32:58 +08:00
idranme
bf72685501 Merge pull request #363 from LLOneBot/dev
3.30.2
2024-08-23 00:30:48 +08:00
idranme
c07467b670 chore: v3.30.2 2024-08-23 00:08:52 +08:00
idranme
ea164fb048 fix: friend list 2024-08-22 23:47:15 +08:00
idranme
0c0ad9a616 Merge pull request #362 from LLOneBot/dev
3.30.1
2024-08-22 20:41:32 +08:00
idranme
7bb4808e2d chore: v3.30.1 2024-08-22 20:18:16 +08:00
idranme
3f7592d06d opt 2024-08-22 20:17:28 +08:00
idranme
2f341fcf43 fix 2024-08-22 18:16:08 +08:00
20 changed files with 114 additions and 258 deletions

View File

@@ -14,7 +14,7 @@ jobs:
- name: setup node - name: setup node
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 18 node-version: 20
- name: install dependenies - name: install dependenies
run: | run: |

View File

@@ -5,7 +5,7 @@ LiteLoaderQQNT 插件,实现 OneBot 11 协议,用于 QQ 机器人开发
> [!CAUTION]\ > [!CAUTION]\
> **请不要在 QQ 官方群聊和任何影响力较大的简中互联网平台(包括但不限于: 哔哩哔哩,微博,知乎,抖音等)发布和讨论*任何*与本插件存在相关性的信息** > **请不要在 QQ 官方群聊和任何影响力较大的简中互联网平台(包括但不限于: 哔哩哔哩,微博,知乎,抖音等)发布和讨论*任何*与本插件存在相关性的信息**
TG群<https://t.me/+nLZEnpne-pQ1OWFl> TG 群:<https://t.me/+nLZEnpne-pQ1OWFl>
## 安装方法 ## 安装方法

View File

@@ -4,7 +4,7 @@
"name": "LLOneBot", "name": "LLOneBot",
"slug": "LLOneBot", "slug": "LLOneBot",
"description": "实现 OneBot 11 协议,用于 QQ 机器人开发", "description": "实现 OneBot 11 协议,用于 QQ 机器人开发",
"version": "3.30.0", "version": "3.30.5",
"icon": "./icon.webp", "icon": "./icon.webp",
"authors": [ "authors": [
{ {

View File

@@ -25,7 +25,7 @@
"fast-xml-parser": "^4.4.1", "fast-xml-parser": "^4.4.1",
"file-type": "^19.4.1", "file-type": "^19.4.1",
"fluent-ffmpeg": "^2.1.3", "fluent-ffmpeg": "^2.1.3",
"minato": "^3.5.0", "minato": "^3.5.1",
"silk-wasm": "^3.6.1", "silk-wasm": "^3.6.1",
"ws": "^8.18.0" "ws": "^8.18.0"
}, },
@@ -41,5 +41,5 @@
"vite": "^5.4.2", "vite": "^5.4.2",
"vite-plugin-cp": "^4.0.8" "vite-plugin-cp": "^4.0.8"
}, },
"packageManager": "yarn@4.4.0" "packageManager": "yarn@4.4.1"
} }

View File

@@ -5,8 +5,6 @@ import path from 'node:path'
import { getSelfUin } from './data' import { getSelfUin } from './data'
import { DATA_DIR } from './utils' import { DATA_DIR } from './utils'
//export const HOOK_LOG = false
export class ConfigUtil { export class ConfigUtil {
private readonly configPath: string private readonly configPath: string
private config: Config | null = null private config: Config | null = null

View File

@@ -1,45 +1,24 @@
import { import {
type Friend,
type GroupMember, type GroupMember,
type SelfInfo, type SelfInfo,
} from '../ntqqapi/types' } from '../ntqqapi/types'
import { type LLOneBotError } from './types' import { type LLOneBotError } from './types'
import { NTQQGroupApi } from '../ntqqapi/api/group' import { NTQQGroupApi } from '../ntqqapi/api/group'
import { log } from './utils/log'
import { isNumeric } from './utils/helper' import { isNumeric } from './utils/helper'
import { NTQQFriendApi, NTQQUserApi } from '../ntqqapi/api' import { NTQQUserApi } from '../ntqqapi/api'
import { RawMessage } from '../ntqqapi/types' import { RawMessage } from '../ntqqapi/types'
import { getConfigUtil } from './config' import { getConfigUtil } from './config'
import { getBuildVersion } from './utils/QQBasicInfo'
export let friends: Friend[] = []
export const llonebotError: LLOneBotError = { export const llonebotError: LLOneBotError = {
ffmpegError: '', ffmpegError: '',
httpServerError: '', httpServerError: '',
wsServerError: '', wsServerError: '',
otherError: 'LLOneBot 未能正常启动,请检查日志查看错误', otherError: 'LLOneBot 未能正常启动,请检查日志查看错误',
} }
// 群号 -> 群成员map(uid=>GroupMember) // 群号 -> 群成员map(uid=>GroupMember)
export const groupMembers: Map<string, Map<string, GroupMember>> = new Map<string, Map<string, GroupMember>>() export const groupMembers: Map<string, Map<string, GroupMember>> = new Map<string, Map<string, GroupMember>>()
export async function getFriend(uinOrUid: string): Promise<Friend | undefined> {
const filterKey: 'uin' | 'uid' = isNumeric(uinOrUid.toString()) ? 'uin' : 'uid'
const filterValue = uinOrUid
let friend = friends.find((friend) => friend[filterKey] === filterValue.toString())
if (!friend && getBuildVersion() < 26702) {
try {
const _friends = await NTQQFriendApi.getFriends(true)
friend = _friends.find((friend) => friend[filterKey] === filterValue.toString())
if (friend) {
friends.push(friend)
}
} catch (e: any) {
log('刷新好友列表失败', e.stack.toString())
}
}
return friend
}
export async function getGroupMember(groupCode: string | number, memberUinOrUid: string | number) { export async function getGroupMember(groupCode: string | number, memberUinOrUid: string | number) {
const groupCodeStr = groupCode.toString() const groupCodeStr = groupCode.toString()
const memberUinOrUidStr = memberUinOrUid.toString() const memberUinOrUidStr = memberUinOrUid.toString()

View File

@@ -12,10 +12,12 @@ export interface OB11Config {
enableHttpHeart?: boolean enableHttpHeart?: boolean
enableQOAutoQuote: boolean // 快速操作回复自动引用原消息 enableQOAutoQuote: boolean // 快速操作回复自动引用原消息
} }
export interface CheckVersion { export interface CheckVersion {
result: boolean result: boolean
version: string version: string
} }
export interface Config { export interface Config {
enableLLOB: boolean enableLLOB: boolean
ob11: OB11Config ob11: OB11Config

View File

@@ -5,6 +5,7 @@ import { getSession } from '@/ntqqapi/wrapper'
import { BuddyListReqType, NodeIKernelProfileService } from '../services' import { BuddyListReqType, NodeIKernelProfileService } from '../services'
import { NTEventDispatch } from '@/common/utils/EventTask' import { NTEventDispatch } from '@/common/utils/EventTask'
import { LimitedHashTable } from '@/common/utils/table' import { LimitedHashTable } from '@/common/utils/table'
import { pick } from 'cosmokit'
export class NTQQFriendApi { export class NTQQFriendApi {
/** 大于或等于 26702 应使用 getBuddyV2 */ /** 大于或等于 26702 应使用 getBuddyV2 */
@@ -17,14 +18,14 @@ export class NTQQFriendApi {
buddyList: Friend[] buddyList: Friend[]
}[] }[]
}>({ }>({
methodName: NTMethod.FRIENDS, className: NTClass.NODE_STORE_API,
args: [{ force_update: forced }, undefined], methodName: 'getBuddyList',
cbCmd: ReceiveCmdS.FRIENDS, cbCmd: ReceiveCmdS.FRIENDS,
afterFirstCmd: false, afterFirstCmd: false,
}) })
let _friends: Friend[] = [] const _friends: Friend[] = []
for (const fData of data.data) { for (const item of data.data) {
_friends.push(...fData.buddyList) _friends.push(...item.buddyList)
} }
return _friends return _friends
} }
@@ -73,7 +74,7 @@ export class NTQQFriendApi {
} else { } else {
const data = await invoke<{ const data = await invoke<{
buddyCategory: CategoryFriend[] buddyCategory: CategoryFriend[]
userSimpleInfos: Map<string, SimpleInfo> userSimpleInfos: Record<string, SimpleInfo>
}>({ }>({
className: NTClass.NODE_STORE_API, className: NTClass.NODE_STORE_API,
methodName: 'getBuddyList', methodName: 'getBuddyList',
@@ -81,7 +82,11 @@ export class NTQQFriendApi {
cbCmd: ReceiveCmdS.FRIENDS, cbCmd: ReceiveCmdS.FRIENDS,
afterFirstCmd: false, afterFirstCmd: false,
}) })
return Array.from(data.userSimpleInfos.values()) const categoryUids: Map<number, string[]> = new Map()
for (const item of data.buddyCategory) {
categoryUids.set(item.categoryId, item.buddyUids)
}
return Object.values(data.userSimpleInfos).filter(v => v.baseInfo && categoryUids.get(v.baseInfo.categoryId)?.includes(v.uid!))
} }
} }
@@ -102,7 +107,7 @@ export class NTQQFriendApi {
} else { } else {
const data = await invoke<{ const data = await invoke<{
buddyCategory: CategoryFriend[] buddyCategory: CategoryFriend[]
userSimpleInfos: Map<string, SimpleInfo> userSimpleInfos: Record<string, SimpleInfo>
}>({ }>({
className: NTClass.NODE_STORE_API, className: NTClass.NODE_STORE_API,
methodName: 'getBuddyList', methodName: 'getBuddyList',
@@ -110,9 +115,9 @@ export class NTQQFriendApi {
cbCmd: ReceiveCmdS.FRIENDS, cbCmd: ReceiveCmdS.FRIENDS,
afterFirstCmd: false, afterFirstCmd: false,
}) })
data.userSimpleInfos.forEach((value, key) => { for (const item of Object.values(data.userSimpleInfos)) {
retMap.set(value.uin!, value.uid!) retMap.set(item.uin!, item.uid!)
}) }
} }
return retMap return retMap
} }
@@ -141,7 +146,7 @@ export class NTQQFriendApi {
} else { } else {
const data = await invoke<{ const data = await invoke<{
buddyCategory: CategoryFriend[] buddyCategory: CategoryFriend[]
userSimpleInfos: Map<string, SimpleInfo> userSimpleInfos: Record<string, SimpleInfo>
}>({ }>({
className: NTClass.NODE_STORE_API, className: NTClass.NODE_STORE_API,
methodName: 'getBuddyList', methodName: 'getBuddyList',
@@ -149,16 +154,19 @@ export class NTQQFriendApi {
cbCmd: ReceiveCmdS.FRIENDS, cbCmd: ReceiveCmdS.FRIENDS,
afterFirstCmd: false, afterFirstCmd: false,
}) })
return Array.from(data.userSimpleInfos).map(([key, value]) => { const category: Map<number, Pick<CategoryFriend, 'buddyUids' | 'categroyName'>> = new Map()
if (value.baseInfo) { for (const item of data.buddyCategory) {
category.set(item.categoryId, pick(item, ['buddyUids', 'categroyName']))
}
return Object.values(data.userSimpleInfos)
.filter(v => v.baseInfo && category.get(v.baseInfo.categoryId)?.buddyUids.includes(v.uid!))
.map(value => {
return { return {
...value, ...value,
categoryId: value.baseInfo.categoryId, categoryId: value.baseInfo.categoryId,
categroyName: data.buddyCategory.find(e => e.categoryId === value.baseInfo.categoryId)?.categroyName categroyName: category.get(value.baseInfo.categoryId)?.categroyName
} }
} })
return value
})
} }
} }

View File

@@ -98,6 +98,10 @@ export class NTQQGroupApi {
) )
return notifies return notifies
} else { } else {
invoke({
methodName: ReceiveCmdS.GROUP_NOTIFY,
classNameIsRegister: true,
})
return (await invoke<GroupNotifies>({ return (await invoke<GroupNotifies>({
methodName: NTMethod.GET_GROUP_NOTICE, methodName: NTMethod.GET_GROUP_NOTICE,
cbCmd: ReceiveCmdS.GROUP_NOTIFY, cbCmd: ReceiveCmdS.GROUP_NOTIFY,

View File

@@ -1,5 +1,5 @@
import { invoke, NTMethod } from '../ntcall' import { invoke, NTMethod } from '../ntcall'
import { GeneralCallResult } from '../services' import { GeneralCallResult, TmpChatInfoApi } from '../services'
import { RawMessage, SendMessageElement, Peer, ChatType2 } from '../types' import { RawMessage, SendMessageElement, Peer, ChatType2 } from '../types'
import { getSelfNick, getSelfUid } from '../../common/data' import { getSelfNick, getSelfUid } from '../../common/data'
import { getSession } from '@/ntqqapi/wrapper' import { getSession } from '@/ntqqapi/wrapper'
@@ -16,10 +16,22 @@ function generateMsgId() {
} }
export class NTQQMsgApi { export class NTQQMsgApi {
/** 27187 TODO */
static async getTempChatInfo(chatType: ChatType2, peerUid: string) { static async getTempChatInfo(chatType: ChatType2, peerUid: string) {
const session = getSession() const session = getSession()
return session?.getMsgService().getTempChatInfo(chatType, peerUid) if (session) {
return session.getMsgService().getTempChatInfo(chatType, peerUid)
} else {
return await invoke<TmpChatInfoApi>({
methodName: 'nodeIKernelMsgService/getTempChatInfo',
args: [
{
chatType,
peerUid,
},
null,
],
})
}
} }
static async setEmojiLike(peer: Peer, msgSeq: string, emojiId: string, set: boolean = true) { static async setEmojiLike(peer: Peer, msgSeq: string, emojiId: string, set: boolean = true) {

View File

@@ -1,11 +1,11 @@
import { invoke, NTMethod } from '../ntcall' import { invoke, NTMethod } from '../ntcall'
import { GeneralCallResult } from '../services' import { GeneralCallResult } from '../services'
import { User, UserDetailInfoByUin, UserDetailInfoByUinV2, UserDetailInfoListenerArg } from '../types' import { User, UserDetailInfoByUin, UserDetailInfoByUinV2, UserDetailInfoListenerArg } from '../types'
import { friends, groupMembers, getSelfUin } from '@/common/data' import { groupMembers, getSelfUin } from '@/common/data'
import { CacheClassFuncAsync, getBuildVersion } from '@/common/utils' import { CacheClassFuncAsync, getBuildVersion } from '@/common/utils'
import { getSession } from '@/ntqqapi/wrapper' import { getSession } from '@/ntqqapi/wrapper'
import { RequestUtil } from '@/common/utils/request' import { RequestUtil } from '@/common/utils/request'
import { NodeIKernelProfileService, UserDetailSource, ProfileBizType } from '../services' import { NodeIKernelProfileService, UserDetailSource, ProfileBizType, forceFetchClientKeyRetType } from '../services'
import { NodeIKernelProfileListener } from '../listeners' import { NodeIKernelProfileListener } from '../listeners'
import { NTEventDispatch } from '@/common/utils/EventTask' import { NTEventDispatch } from '@/common/utils/EventTask'
import { NTQQFriendApi } from './friend' import { NTQQFriendApi } from './friend'
@@ -146,39 +146,37 @@ export class NTQQUserApi {
return (hash & 0x7fffffff).toString() return (hash & 0x7fffffff).toString()
} }
/** 27187 TODO */
static async getPSkey(domains: string[]): Promise<Map<string, string>> {
const session = getSession()
const res = await session?.getTipOffService().getPskey(domains, true)
if (res?.result !== 0) {
throw new Error(`获取Pskey失败: ${res?.errMsg}`)
}
return res.domainPskeyMap
}
/** 27187 TODO */
static async like(uid: string, count = 1) { static async like(uid: string, count = 1) {
const session = getSession() const session = getSession()
return session?.getProfileLikeService().setBuddyProfileLike({ if (session) {
friendUid: uid, return session.getProfileLikeService().setBuddyProfileLike({
sourceId: 71, friendUid: uid,
doLikeCount: count, sourceId: 71,
doLikeTollCount: 0 doLikeCount: count,
}) doLikeTollCount: 0
})
} else {
return await invoke<GeneralCallResult & { succCounts: number }>({
methodName: 'nodeIKernelProfileLikeService/setBuddyProfileLike',
args: [
{
doLikeUserInfo: {
friendUid: uid,
sourceId: 71,
doLikeCount: count,
doLikeTollCount: 0
}
},
null,
],
})
}
} }
static async getUidByUinV1(Uin: string) { static async getUidByUinV1(Uin: string) {
const session = getSession() const session = getSession()
// 通用转换开始尝试 // 通用转换开始尝试
let uid = (await session?.getUixConvertService().getUid([Uin]))?.uidInfo.get(Uin) let uid = (await session?.getUixConvertService().getUid([Uin]))?.uidInfo.get(Uin)
// Uid 好友转
if (!uid) {
friends.forEach((t) => {
if (t.uin == Uin) {
uid = t.uid
}
})
}
//Uid 群友列表转 //Uid 群友列表转
if (!uid) { if (!uid) {
for (let groupMembersList of groupMembers.values()) { for (let groupMembersList of groupMembers.values()) {
@@ -283,14 +281,6 @@ export class NTQQUserApi {
[Uid] [Uid]
) )
let uin = ret.uinInfo.get(Uid) let uin = ret.uinInfo.get(Uid)
if (!uin) {
//从Buddy缓存获取Uin
friends.forEach((t) => {
if (t.uid == Uid) {
uin = t.uin
}
})
}
if (!uin) { if (!uin) {
uin = (await NTQQUserApi.getUserDetailInfo(Uid)).uin //从QQ Native 转换 uin = (await NTQQUserApi.getUserDetailInfo(Uid)).uin //从QQ Native 转换
} }
@@ -348,9 +338,17 @@ export class NTQQUserApi {
return await NTQQUserApi.getUinByUidV1(Uid) return await NTQQUserApi.getUinByUidV1(Uid)
} }
/** 27187 TODO */
static async forceFetchClientKey() { static async forceFetchClientKey() {
const session = getSession() const session = getSession()
return await session?.getTicketService().forceFetchClientKey('') if (session) {
return await session.getTicketService().forceFetchClientKey('')
} else {
return await invoke<forceFetchClientKeyRetType>({
methodName: 'nodeIKernelTicketService/forceFetchClientKey',
args: [{
domain: ''
}, null],
})
}
} }
} }

View File

@@ -178,29 +178,6 @@ export class WebApi {
return memberData return memberData
} }
static async setGroupNotice(GroupCode: string, Content: string = '') {
//https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?bkn=${bkn}
//qid=${群号}&bkn=${bkn}&text=${内容}&pinned=0&type=1&settings={"is_show_edit_card":1,"tip_window_type":1,"confirm_required":1}
const _Pskey = (await NTQQUserApi.getPSkey(['qun.qq.com']))['qun.qq.com']
const _Skey = await NTQQUserApi.getSkey()
const CookieValue = 'p_skey=' + _Pskey + '; skey=' + _Skey + '; p_uin=o' + getSelfUin()
let ret: any = undefined
//console.log(CookieValue)
if (!_Skey || !_Pskey) {
//获取Cookies失败
return undefined
}
const Bkn = WebApi.genBkn(_Skey)
const data = 'qid=' + GroupCode + '&bkn=' + Bkn + '&text=' + Content + '&pinned=0&type=1&settings={"is_show_edit_card":1,"tip_window_type":1,"confirm_required":1}'
const url = 'https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?bkn=' + Bkn
try {
ret = await RequestUtil.HttpGetJson<any>(url, 'GET', '', { 'Cookie': CookieValue })
return ret
} catch (e) {
return undefined
}
}
static genBkn(sKey: string) { static genBkn(sKey: string) {
sKey = sKey || ''; sKey = sKey || '';
let hash = 5381; let hash = 5381;
@@ -220,7 +197,7 @@ export class WebApi {
let res = ''; let res = '';
let resJson; let resJson;
try { try {
res = await RequestUtil.HttpGetText(url, 'GET', '', { 'Cookie': CookieValue }); res = await RequestUtil.HttpGetText(url, 'GET', '', { 'Cookie': cookieStr });
const match = res.match(/window\.__INITIAL_STATE__=(.*?);/); const match = res.match(/window\.__INITIAL_STATE__=(.*?);/);
if (match) { if (match) {
resJson = JSON.parse(match[1].trim()); resJson = JSON.parse(match[1].trim());
@@ -237,7 +214,8 @@ export class WebApi {
} }
let HonorInfo: any = { group_id: groupCode }; let HonorInfo: any = { group_id: groupCode };
const CookieValue = (await NTQQUserApi.getCookies('qun.qq.com')).cookies; const cookieObject = await NTQQUserApi.getCookies('qun.qq.com')
const cookieStr = Object.entries(cookieObject).map(([key, value]) => `${key}=${value}`).join('; ')
if (getType === WebHonorType.TALKACTIVE || getType === WebHonorType.ALL) { if (getType === WebHonorType.TALKACTIVE || getType === WebHonorType.ALL) {
try { try {

View File

@@ -1,17 +1,16 @@
import type { BrowserWindow } from 'electron' import type { BrowserWindow } from 'electron'
import { NTClass, NTMethod } from './ntcall' import { NTClass, NTMethod } from './ntcall'
import { NTQQMsgApi } from './api/msg' import { NTQQMsgApi, NTQQFriendApi } from './api'
import { import {
CategoryFriend, CategoryFriend,
ChatType, ChatType,
GroupMember, GroupMember,
GroupMemberRole, GroupMemberRole,
RawMessage, RawMessage,
SimpleInfo, User, SimpleInfo,
User
} from './types' } from './types'
import { import {
friends,
getFriend,
getGroupMember, getGroupMember,
setSelfInfo setSelfInfo
} from '@/common/data' } from '@/common/data'
@@ -224,116 +223,7 @@ export function removeReceiveHook(id: string) {
receiveHooks.splice(index, 1) receiveHooks.splice(index, 1)
} }
//let activatedGroups: string[] = []
/*async function updateGroups(_groups: Group[], needUpdate: boolean = true) {
for (let group of _groups) {
log('update group', group.groupCode)
if (group.privilegeFlag === 0) {
deleteGroup(group.groupCode)
continue
}
//log('update group', group)
NTQQMsgApi.activateChat({ peerUid: group.groupCode, chatType: ChatType.group }).then().catch(log)
let existGroup = groups.find((g) => g.groupCode == group.groupCode)
if (existGroup) {
Object.assign(existGroup, group)
} else {
groups.push(group)
existGroup = group
}
if (needUpdate) {
const members = await NTQQGroupApi.getGroupMembers(group.groupCode)
if (members) {
existGroup.members = Array.from(members.values())
}
}
}
}*/
/*async function processGroupEvent(payload: { groupList: Group[] }) {
try {
const newGroupList = payload.groupList
for (const group of newGroupList) {
let existGroup = groups.find((g) => g.groupCode == group.groupCode)
if (existGroup) {
if (existGroup.memberCount > group.memberCount) {
log(`群(${group.groupCode})成员数量减少${existGroup.memberCount} -> ${group.memberCount}`)
const oldMembers = existGroup.members
await sleep(200) // 如果请求QQ API的速度过快通常无法正确拉取到最新的群信息因此这里人为引入一个延时
const newMembers = await NTQQGroupApi.getGroupMembers(group.groupCode)
group.members = Array.from(newMembers.values())
const newMembersSet = new Set<string>() // 建立索引降低时间复杂度
for (const member of newMembers) {
newMembersSet.add(member[1].uin)
}
// 判断bot是否是管理员如果是管理员不需要从这里得知有人退群这里的退群无法得知是主动退群还是被踢
const selfUin = getSelfUin()
const bot = await getGroupMember(group.groupCode, selfUin)
if (bot?.role == GroupMemberRole.admin || bot?.role == GroupMemberRole.owner) {
continue
}
for (const member of oldMembers) {
if (!newMembersSet.has(member.uin) && member.uin != selfUin) {
postOb11Event(
new OB11GroupDecreaseEvent(
parseInt(group.groupCode),
parseInt(member.uin),
parseInt(member.uin),
'leave',
),
)
break
}
}
}
if (group.privilegeFlag === 0) {
deleteGroup(group.groupCode)
}
}
}
updateGroups(newGroupList, false).then()
} catch (e: any) {
updateGroups(payload.groupList).then()
log('更新群信息错误', e.stack.toString())
}
}*/
export async function startHook() { export async function startHook() {
// 群列表变动
/*registerReceiveHook<{ groupList: Group[]; updateType: number }>(ReceiveCmdS.GROUPS, (payload) => {
// updateType 3是群列表变动2是群成员变动
// log("群列表变动", payload.updateType, payload.groupList)
if (payload.updateType != 2) {
updateGroups(payload.groupList).then()
}
else {
if (process.platform == 'win32') {
processGroupEvent(payload).then()
}
}
})
registerReceiveHook<{ groupList: Group[]; updateType: number }>(ReceiveCmdS.GROUPS_STORE, (payload) => {
// updateType 3是群列表变动2是群成员变动
// log("群列表变动, store", payload.updateType, payload.groupList)
if (payload.updateType != 2) {
updateGroups(payload.groupList).then()
}
else {
if (process.platform != 'win32') {
processGroupEvent(payload).then()
}
}
})*/
registerReceiveHook<{ registerReceiveHook<{
groupCode: string groupCode: string
dataSource: number dataSource: number
@@ -402,13 +292,6 @@ export async function startHook() {
log('好友列表变动', friendList.length) log('好友列表变动', friendList.length)
for (let friend of friendList) { for (let friend of friendList) {
NTQQMsgApi.activateChat({ peerUid: friend.uid, chatType: ChatType.friend }).then() NTQQMsgApi.activateChat({ peerUid: friend.uid, chatType: ChatType.friend }).then()
let existFriend = friends.find((f) => f.uin == friend.uin)
if (!existFriend) {
friends.push(friend)
}
else {
Object.assign(existFriend, friend)
}
} }
}) })
@@ -506,11 +389,8 @@ export async function startHook() {
if (isNumeric(peerUid)) { if (isNumeric(peerUid)) {
chatType = ChatType.group chatType = ChatType.group
} }
else { else if (!(await NTQQFriendApi.isBuddy(peerUid))) {
// 检查是否好友 chatType = ChatType.temp
if (!(await getFriend(peerUid))) {
chatType = ChatType.temp
}
} }
const peer = { peerUid, chatType } const peer = { peerUid, chatType }
await sleep(1000) await sleep(1000)

View File

@@ -82,7 +82,8 @@ export interface CategoryFriend {
categroyName: string categroyName: string
categroyMbCount: number categroyMbCount: number
onlineCount: number onlineCount: number
buddyList: User[] buddyList: User[] // V1
buddyUids: string[]
} }
export interface CoreInfo { export interface CoreInfo {

View File

@@ -63,7 +63,7 @@ export abstract class GetFileBase extends BaseAction<GetFilePayload, GetFileResp
} else if (fileCache[0].elementType === ElementType.VIDEO) { } else if (fileCache[0].elementType === ElementType.VIDEO) {
res.url = await NTQQFileApi.getVideoUrl(peer, fileCache[0].msgId, fileCache[0].elementId) res.url = await NTQQFileApi.getVideoUrl(peer, fileCache[0].msgId, fileCache[0].elementId)
} }
if (enableLocalFile2Url && downloadPath && res.file === res.url) { if (enableLocalFile2Url && downloadPath && (res.file === res.url || res.url === undefined)) {
try { try {
res.base64 = await fsPromise.readFile(downloadPath, 'base64') res.base64 = await fsPromise.readFile(downloadPath, 'base64')
} catch (e) { } catch (e) {

View File

@@ -15,10 +15,13 @@ export class GetCookies extends BaseAction<Payload, Response> {
actionName = ActionName.GetCookies actionName = ActionName.GetCookies
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
if (!payload.domain) {
throw '缺少参数 domain'
}
const cookiesObject = await NTQQUserApi.getCookies(payload.domain) const cookiesObject = await NTQQUserApi.getCookies(payload.domain)
//把获取到的cookiesObject转换成 k=v; 格式字符串拼接在一起 //把获取到的cookiesObject转换成 k=v; 格式字符串拼接在一起
const cookies = Object.entries(cookiesObject).map(([key, value]) => `${key}=${value}`).join('; ') const cookies = Object.entries(cookiesObject).map(([key, value]) => `${key}=${value}`).join('; ')
const bkn = WebApi.genBkn(cookiesObject.p_skey) const bkn = cookiesObject.skey ? WebApi.genBkn(cookiesObject.skey) : ''
return { cookies, bkn } return { cookies, bkn }
} }
} }

View File

@@ -1,7 +1,6 @@
import BaseAction from '../BaseAction' import BaseAction from '../BaseAction'
import { OB11User } from '../../types' import { OB11User } from '../../types'
import { OB11Constructor } from '../../constructor' import { OB11Constructor } from '../../constructor'
import { friends } from '@/common/data'
import { ActionName } from '../types' import { ActionName } from '../types'
import { NTQQFriendApi } from '@/ntqqapi/api' import { NTQQFriendApi } from '@/ntqqapi/api'
import { getBuildVersion } from '@/common/utils/QQBasicInfo' import { getBuildVersion } from '@/common/utils/QQBasicInfo'
@@ -14,24 +13,17 @@ export class GetFriendList extends BaseAction<Payload, OB11User[]> {
actionName = ActionName.GetFriendList actionName = ActionName.GetFriendList
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const refresh = payload?.no_cache === true || payload?.no_cache === 'true'
if (getBuildVersion() >= 26702) { if (getBuildVersion() >= 26702) {
return OB11Constructor.friendsV2(await NTQQFriendApi.getBuddyV2(payload?.no_cache === true || payload?.no_cache === 'true')) return OB11Constructor.friendsV2(await NTQQFriendApi.getBuddyV2(refresh))
} }
if (friends.length === 0 || payload?.no_cache === true || payload?.no_cache === 'true') { return OB11Constructor.friends(await NTQQFriendApi.getFriends(refresh))
const _friends = await NTQQFriendApi.getFriends(true)
// log('强制刷新好友列表,结果: ', _friends)
if (_friends.length > 0) {
friends.length = 0
friends.push(..._friends)
}
}
return OB11Constructor.friends(friends)
} }
} }
// extend // extend
export class GetFriendWithCategory extends BaseAction<void, any> { export class GetFriendWithCategory extends BaseAction<void, any> {
actionName = ActionName.GetFriendsWithCategory; actionName = ActionName.GetFriendsWithCategory
protected async _handle(payload: void) { protected async _handle(payload: void) {
if (getBuildVersion() >= 26702) { if (getBuildVersion() >= 26702) {

View File

@@ -3,8 +3,8 @@ import { ActionName } from '../types'
import { NTQQUserApi } from '@/ntqqapi/api' import { NTQQUserApi } from '@/ntqqapi/api'
interface Payload { interface Payload {
user_id: number user_id: number | string
times: number times: number | string
} }
export default class SendLike extends BaseAction<Payload, null> { export default class SendLike extends BaseAction<Payload, null> {
@@ -14,7 +14,7 @@ export default class SendLike extends BaseAction<Payload, null> {
try { try {
const qq = payload.user_id.toString() const qq = payload.user_id.toString()
const uid: string = await NTQQUserApi.getUidByUin(qq) || '' const uid: string = await NTQQUserApi.getUidByUin(qq) || ''
const result = await NTQQUserApi.like(uid, parseInt(payload.times?.toString()) || 1) const result = await NTQQUserApi.like(uid, +payload.times || 1)
if (result?.result !== 0) { if (result?.result !== 0) {
throw Error(result?.errMsg) throw Error(result?.errMsg)
} }

View File

@@ -49,6 +49,7 @@ import { OB11GroupRecallNoticeEvent } from './event/notice/OB11GroupRecallNotice
import { OB11FriendPokeEvent, OB11GroupPokeEvent } from './event/notice/OB11PokeEvent' import { OB11FriendPokeEvent, OB11GroupPokeEvent } from './event/notice/OB11PokeEvent'
import { OB11BaseNoticeEvent } from './event/notice/OB11BaseNoticeEvent' import { OB11BaseNoticeEvent } from './event/notice/OB11BaseNoticeEvent'
import { OB11GroupEssenceEvent } from './event/notice/OB11GroupEssenceEvent' import { OB11GroupEssenceEvent } from './event/notice/OB11GroupEssenceEvent'
import { omit } from 'cosmokit'
export class OB11Constructor { export class OB11Constructor {
static async message(msg: RawMessage): Promise<OB11Message> { static async message(msg: RawMessage): Promise<OB11Message> {
@@ -661,7 +662,7 @@ export class OB11Constructor {
for (const friend of friends) { for (const friend of friends) {
const sexValue = this.sex(friend.baseInfo.sex!) const sexValue = this.sex(friend.baseInfo.sex!)
data.push({ data.push({
...friend.baseInfo, ...omit(friend.baseInfo, ['richBuffer']),
...friend.coreInfo, ...friend.coreInfo,
user_id: parseInt(friend.coreInfo.uin), user_id: parseInt(friend.coreInfo.uin),
nickname: friend.coreInfo.nick, nickname: friend.coreInfo.nick,

View File

@@ -1 +1 @@
export const version = '3.30.0' export const version = '3.30.5'