diff --git a/lib/core/base-client.ts b/lib/core/base-client.ts index 2af8b1fe..9bcc0a9d 100644 --- a/lib/core/base-client.ts +++ b/lib/core/base-client.ts @@ -119,7 +119,7 @@ export class BaseClient extends EventEmitter { /** 随心跳一起触发的函数,可以随意设定 */ protected heartbeat = NOOP // 心跳定时器 - private [HEARTBEAT]: NodeJS.Timeout + private [HEARTBEAT]?: NodeJS.Timeout /** 数据统计 */ protected readonly statistics = { start_time: timestamp(), diff --git a/lib/friend.ts b/lib/friend.ts index b20bb303..94bfd0b3 100644 --- a/lib/friend.ts +++ b/lib/friend.ts @@ -9,6 +9,7 @@ import { Sendable, PrivateMessage, buildMusic, MusicPlatform, Quotable, rand2uui import { buildSyncCookie, Contactable, highwayHttpUpload, CmdID } from "./internal" import { MessageRet } from "./events" import { FriendInfo } from "./entities" +import { buildShare,type ShareConfig, type ShareContent } from "./message/share" type Client = import("./client").Client @@ -150,10 +151,12 @@ export class User extends Contactable { private _getRouting(file = false): pb.Encodable { if (Reflect.has(this, "gid")) - return { 3: { - 1: code2uin(Reflect.get(this, "gid")), - 2: this.uid, - } } + return { + 3: { + 1: code2uin(Reflect.get(this, "gid")), + 2: this.uid, + } + } return file ? { 15: { 1: this.uid, 2: 4 } } : { 1: { 1: this.uid } } } @@ -314,7 +317,7 @@ export class Friend extends User { let friend = weakmap.get(info!) if (friend) return friend friend = new Friend(this, Number(uid), info) - if (info) + if (info) weakmap.set(info, friend) return friend } @@ -351,9 +354,15 @@ export class Friend extends User { await this.c.sendOidb("OidbSvc.0xb77_9", pb.encode(body)) } + /** 发送网址分享 */ + async shareUrl(content: ShareContent, config: ShareConfig) { + const body = buildShare(this.uid, 0, content, config) + await this.c.sendOidb("OidbSvc.0xb77_9", pb.encode(body)) + } + /** 设置备注 */ async setRemark(remark: string) { - const req = jce.encodeStruct([ this.uid, String(remark || "") ]) + const req = jce.encodeStruct([this.uid, String(remark || "")]) const body = jce.encodeWrapper({ req }, "KQQ.ProfileService.ProfileServantObj", "ChangeFriendName") await this.c.sendUni("ProfileService.ChangeFriendName", body) } @@ -426,7 +435,7 @@ export class Friend extends User { } else { file = String(file) filesize = (await fs.promises.stat(file)).size - ;[filemd5, filesha] = await fileHash(file) + ;[filemd5, filesha] = await fileHash(file) filename = filename ? String(filename) : path.basename(file) filestream = fs.createReadStream(file, { highWaterMark: 524288 }) } diff --git a/lib/group.ts b/lib/group.ts index aa4b9ef0..73146bf9 100644 --- a/lib/group.ts +++ b/lib/group.ts @@ -8,6 +8,7 @@ import { Sendable, GroupMessage, Image, ImageElem, buildMusic, MusicPlatform, An import { Gfs } from "./gfs" import { MessageRet } from "./events" import { GroupInfo, MemberInfo } from "./entities" +import { buildShare, type ShareConfig, type ShareContent } from "./message/share" type Client = import("./client").Client @@ -140,7 +141,7 @@ export class Group extends Discuss { /** 获取群头像url (history=1,2,3...) */ getAvatarUrl(size: 0 | 40 | 100 | 140 = 0, history = 0) { - return `https://p.qlogo.cn/gh/${this.gid}/${this.gid}${history?"_"+history:""}/` + size + return `https://p.qlogo.cn/gh/${this.gid}/${this.gid}${history ? "_" + history : ""}/` + size } /** 强制刷新资料 */ @@ -178,7 +179,7 @@ export class Group extends Discuss { active_member_count: proto[37], update_time: timestamp(), } - info = Object.assign(this.c.gl.get(this.gid) || this._info || { }, info) + info = Object.assign(this.c.gl.get(this.gid) || this._info || {}, info) this.c.gl.set(this.gid, info) this._info = info weakmap.set(info, this) @@ -218,7 +219,7 @@ export class Group extends Discuss { update_time: 0, } const list = this.c.gml.get(this.gid)! - info = Object.assign(list.get(v[0]) || { }, info) + info = Object.assign(list.get(v[0]) || {}, info) if (this.c.gl.get(this.gid)?.owner_id === v[0]) info.role = "owner" list.set(v[0], info) @@ -256,6 +257,13 @@ export class Group extends Discuss { await this.c.sendOidb("OidbSvc.0xb77_9", pb.encode(body)) } + /** 发送网址分享 */ + async shareUrl(content: ShareContent, config: ShareConfig) { + const body = buildShare(this.gid, 1, content, config) + this.c.logger.trace('url share', body) + await this.c.sendOidb("OidbSvc.0xb77_9", pb.encode(body)) + } + /** * 发送一条消息 * @param source 引用回复的消息 @@ -312,7 +320,7 @@ export class Group extends Discuss { this.c.logger.info(`succeed to send: [Group(${this.gid})] ` + converter.brief) { const { seq, rand, time } = parseGroupMessageId(message_id) - return { seq, rand, time, message_id} + return { seq, rand, time, message_id } } } @@ -413,7 +421,7 @@ export class Group extends Discuss { announce(content: string) { return this._setting({ 4: String(content) }) } - private async _setting(obj: {[tag: number]: any}) { + private async _setting(obj: { [tag: number]: any }) { const body = pb.encode({ 1: this.gid, 2: obj diff --git a/lib/message/share.ts b/lib/message/share.ts new file mode 100644 index 00000000..23cc33bb --- /dev/null +++ b/lib/message/share.ts @@ -0,0 +1,63 @@ + +/**所有可选参数默认为QQ浏览器 */ +export interface ShareConfig { + appid?: number, + // style?: number, + appname?: string, + /**app签名hash */ + appsign?: string, +} + +export interface ShareContent { + title: string, + summary?: string, + /**从消息列表中看到的文字,默认为 "[分享]"+title */ + abstract?: string, + /**预览图网址, 默认为QQ浏览器图标,似乎对域名有限制 */ + preview?: string, + /**跳转链接, 没有则发不出 */ + jumpUrl: string, + musicUrl?: string +} + +enum app { + qq = 100446242, + mi = 1105414497, + quark = 1105781586 +} + + +const defaultConfig: Required = { + appid: app.qq, + // style: 4,//有音乐4 没音乐0 + appname: 'com.tencent.mtt', + appsign: 'd8391a394d4a179e6fe7bdb8a301258b', +} +/** + * @param target 目标qq + * @param bu 0为私聊 1为群聊 + */ +export function buildShare(target: number, bu: 0 | 1, content: ShareContent, config: ShareConfig = {}) { + config = { ...defaultConfig, ...config } + return { + 1: config.appid, + 2: 1, + 3: content.musicUrl ? 4 : 0, + 5: { + 1: 1, + 2: "0.0.0", + 3: config.appname, + 4: config.appsign + }, + 10: bu, + 11: target, + 12: { + 10: content.title, + 11: content.summary, + 12: content.abstract, + 13: content.jumpUrl, + 14: content.preview /* ?? 'https://tangram-1251316161.file.myqcloud.com/files/20210721/e50a8e37e08f29bf1ffc7466e1950690.png' */, + 16: content.musicUrl, + } + } +} \ No newline at end of file