Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/更新日志.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
V7.12.9
更新时间 2026-04-29

* OneBot 修复 get_group_member_info API 可能获取不到性别与年龄
* OneBot 支持 get_stranger_info API 获取是否会员、是否年费会员、会员等级、备注

=================
V7.12.8
更新时间 2026-04-28

Expand Down
2 changes: 1 addition & 1 deletion package-dist.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"name":"llonebot-dist","version":"7.12.8","type":"module","description":"","main":"llbot.js","author":"linyuchen","repository":{"type":"git","url":"https://github.com/LLOneBot/LuckyLilliaBot"}}
{"name":"llonebot-dist","version":"7.12.9","type":"module","description":"","main":"llbot.js","author":"linyuchen","repository":{"type":"git","url":"https://github.com/LLOneBot/LuckyLilliaBot"}}
9 changes: 9 additions & 0 deletions src/main/pmhq/mixins/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ export function UserMixin<T extends new (...args: any[]) => PMHQBase>(Base: T) {
uin,
keys: [
{ key: 102 }, // 个性签名
{ key: 103 }, // 备注
{ key: 104 }, // 标签
{ key: 105 }, // 等级
{ key: 107 }, // 业务列表
{ key: 20002 }, // 昵称
{ key: 20003 }, // 国家
{ key: 20009 }, // 性别
{ key: 20020 }, // 城市
{ key: 20021 }, // 学校
{ key: 20026 }, // 注册时间
{ key: 20031 }, // 生日
{ key: 20037 }, // 年龄
Expand All @@ -32,6 +35,7 @@ export function UserMixin<T extends new (...args: any[]) => PMHQBase>(Base: T) {
const info = Oidb.FetchUserInfoResp.decode(oidbRespBody)
const numbers = Object.fromEntries(info.body.properties.numberProperties.map(p => [p.key, p.value]))
const bytes = Object.fromEntries(info.body.properties.bytesProperties.map(p => [p.key, p.value]))
const business = bytes[107] ? Misc.UserInfoBusiness.decode(bytes[107]) : undefined
return {
uin: info.body.uin,
nick: bytes[20002]?.toString() ?? '',
Comment on lines +38 to 41
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): 请在 lists 本身上使用可选链,以避免在其缺失或为空时出现运行时错误。

business?.body.lists[0] 仍然假定 lists 存在且可索引;如果 body.listsundefined 或不是数组,就会抛异常。请改为使用 business?.body.lists?.[0](其它位置同理),或者先赋值 const first = business?.body.lists?.[0],然后在 isVipisYearsVipvipLevel 中复用 first,以便在 proto 数据异常时也能安全处理。

Original comment in English

issue (bug_risk): Use optional chaining on lists itself to avoid possible runtime errors when it is missing or empty.

business?.body.lists[0] still assumes lists exists and is indexable; if body.lists is undefined or not an array, this will throw. Please either use business?.body.lists?.[0] (and similarly elsewhere) or assign const first = business?.body.lists?.[0] and reuse first for isVip, isYearsVip, and vipLevel to safely handle malformed proto data.

Expand All @@ -47,6 +51,11 @@ export function UserMixin<T extends new (...args: any[]) => PMHQBase>(Base: T) {
birthdayMonth: bytes[20031]?.[2] ?? 0,
birthdayDay: bytes[20031]?.[3] ?? 0,
labels: bytes[104] ? Misc.UserInfoLabel.decode(bytes[104]).labels.map(e => e.content) : [],
school: bytes[20021]?.toString() ?? '',
remark: bytes[103]?.toString() ?? '',
isVip: !!business?.body.lists[0],
isYearsVip: !!business?.body.lists[0]?.isYear,
vipLevel: business?.body.lists[0]?.level ?? 0
}
}

Expand Down
36 changes: 13 additions & 23 deletions src/milky/api/system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,29 +80,19 @@ const GetUserProfile = defineApi(
GetUserProfileInput,
GetUserProfileOutput,
async (ctx, payload) => {
const userInfo = await ctx.ntUserApi.getUserDetailInfoByUin(payload.user_id.toString())
if (userInfo.result !== 0) {
return Failed(-500, userInfo.errMsg)
}
const profile = {
nickname: userInfo.detail.simpleInfo.coreInfo.nick,
qid: userInfo.detail.simpleInfo.baseInfo.qid,
age: userInfo.detail.simpleInfo.baseInfo.age,
sex: transformGender(userInfo.detail.simpleInfo.baseInfo.sex),
remark: userInfo.detail.simpleInfo.coreInfo.remark,
bio: userInfo.detail.simpleInfo.baseInfo.longNick,
level: userInfo.detail.commonExt?.qqLevel ?
(userInfo.detail.commonExt.qqLevel.penguinNum * 256 + userInfo.detail.commonExt.qqLevel.crownNum * 64 +
userInfo.detail.commonExt.qqLevel.sunNum * 16 + userInfo.detail.commonExt.qqLevel.moonNum * 4 +
userInfo.detail.commonExt.qqLevel.starNum) : 0,
country: userInfo.detail.commonExt?.country || '',
city: userInfo.detail.commonExt?.city || '',
school: userInfo.detail.commonExt?.college || '',
}
if (profile.level === 0) {
profile.level = (await ctx.pmhq.fetchUserInfo(payload.user_id)).level
}
return Ok(profile)
const info = await ctx.pmhq.fetchUserInfo(payload.user_id)
return Ok({
nickname: info.nick,
qid: info.qid,
age: info.age,
sex: transformGender(info.sex),
remark: info.remark,
bio: info.longNick,
level: info.level,
country: info.country,
city: info.city,
school: info.school,
})
}
)

Expand Down
15 changes: 15 additions & 0 deletions src/ntqqapi/proto/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,19 @@ export namespace Misc {
content: ProtoField(4, 'string')
}, 'repeated')
})

export const UserInfoBusiness = ProtoMessage.of({
body: ProtoField(3, {
msg: ProtoField(1, 'string'),
lists: ProtoField(3, {
type: ProtoField(1, 'uint32'),
field2: ProtoField(2, 'uint32'),
isYear: ProtoField(3, 'uint32'),
level: ProtoField(4, 'uint32'),
isPro: ProtoField(5, 'uint32'),
icon1: ProtoField(6, 'string'),
icon2: ProtoField(7, 'string')
}, 'repeated')
})
})
}
10 changes: 9 additions & 1 deletion src/onebot11/action/go-cqhttp/GetStrangerInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ interface Response extends OB11User {
city: string
country: string
labels: string[]
is_vip: boolean
is_years_vip: boolean
vip_level: number
remark: string
}

export class GetStrangerInfo extends BaseAction<Payload, Response> {
Expand Down Expand Up @@ -43,7 +47,11 @@ export class GetStrangerInfo extends BaseAction<Payload, Response> {
birthday_year: info.birthdayYear,
birthday_month: info.birthdayMonth,
birthday_day: info.birthdayDay,
labels: info.labels
labels: info.labels,
is_vip: info.isVip,
is_years_vip: info.isYearsVip,
vip_level: info.vipLevel,
remark: info.remark
}
}
}
20 changes: 11 additions & 9 deletions src/onebot11/action/group/GetGroupMemberInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,25 @@ class GetGroupMemberInfo extends BaseAction<Payload, OB11GroupMember> {
let info: UserDetailInfo | undefined
try {
info = await this.ctx.ntUserApi.getUserDetailInfoWithBizInfo(member.uid)
this.ctx.logger.info('getUserDetailInfoWithBizInfo')
} catch (e) {
try {
const fetchInfo = await this.ctx.ntUserApi.fetchUserDetailInfo(member.uid)
info = fetchInfo.detail.get(member.uid)
this.ctx.logger.info('fetchUserDetailInfo')
} catch (e) {
}
}
if (info) {
this.ctx.logger.info(info)
if (info?.commonExt) {
ret.sex = OB11Entities.sex(info.simpleInfo.baseInfo.sex)
ret.qq_level = info.commonExt?.qqLevel && calcQQLevel(info.commonExt.qqLevel) || 0
ret.age = info.simpleInfo.baseInfo.age ?? 0
}
if (ret.qq_level === 0) {
ret.qq_level = (await this.ctx.pmhq.fetchUserInfo(+payload.user_id)).level
ret.qq_level = calcQQLevel(info.commonExt.qqLevel)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: 在调用 calcQQLevel 之前,请处理 info.commonExt 存在但 qqLevel 缺失或格式不正确的情况。

之前的版本会在 info.commonExt?.qqLevel 上短路,所以当 qqLevel 缺失时不会调用 calcQQLevel。现在只要 commonExt 存在就会执行 calcQQLevel(info.commonExt.qqLevel)。如果 qqLevel 可能为 undefined 或结构异常,这可能会抛出异常或产生错误结果。建议恢复保护判断,或者让 calcQQLevelundefined/无效输入更加健壮。

Original comment in English

issue: Handle cases where info.commonExt exists but qqLevel is missing or malformed before calling calcQQLevel.

The previous version short-circuited on info.commonExt?.qqLevel, so calcQQLevel was never called when qqLevel was missing. Now calcQQLevel(info.commonExt.qqLevel) runs whenever commonExt exists. If qqLevel can be undefined or have an unexpected shape, this may throw or yield wrong results. Consider reinstating a guard or making calcQQLevel robust to undefined/invalid input.

ret.age = info.simpleInfo.baseInfo.age
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): 建议为 age 提供一个默认值,以避免向下游传递 undefined

之前通过 age ?? 0 可以保证 ret.age 一定是数字。现在的新赋值方式下,当 baseInfo.age 缺失时,ret.age 可能变为 undefined,这可能会破坏那些假定年龄为数值的调用方。请恢复一个兜底逻辑(例如 ret.age = info.simpleInfo.baseInfo.age ?? 0)以保持原有行为。

Original comment in English

issue (bug_risk): Consider providing a default value for age to avoid passing undefined downstream.

Previously ret.age was guaranteed to be a number via age ?? 0. With the new assignment, ret.age can become undefined when baseInfo.age is missing, which may break callers that assume a numeric age. Please restore a fallback (e.g., ret.age = info.simpleInfo.baseInfo.age ?? 0) to preserve the prior behavior.

if (ret.qq_level === 0) {
ret.qq_level = (await this.ctx.pmhq.fetchUserInfo(+payload.user_id)).level
}
} else {
const info = await this.ctx.pmhq.fetchUserInfo(+payload.user_id)
ret.sex = OB11Entities.sex(info.sex)
ret.qq_level = info.level
ret.age = info.age
}
return ret
}
Expand Down
2 changes: 1 addition & 1 deletion src/version.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const version = '7.12.8'
export const version = '7.12.9'
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1596,13 +1596,13 @@ __metadata:
linkType: hard

"postcss@npm:^8.5.10":
version: 8.5.10
resolution: "postcss@npm:8.5.10"
version: 8.5.12
resolution: "postcss@npm:8.5.12"
dependencies:
nanoid: "npm:^3.3.11"
picocolors: "npm:^1.1.1"
source-map-js: "npm:^1.2.1"
checksum: 10c0/c592dffa0c4873b401f01955b265538d9942f425040df5e2b8f0ad34c83773a792ea0fa5859ccc99cfb5b955b4ebff118ab7056315388dc83b107b0fa8313576
checksum: 10c0/5baebaf574c567bc1b3d61197f38af4ce5920b8f611c887fb6bc3dcc14af00253c169dbf19897bc889cce0b0d9818ab5eb4ea0caedf02b0bab10da8a43ce8c12
languageName: node
linkType: hard

Expand Down
Loading