+5
-2
@@ -5,2 +5,3 @@ /// <reference types="node" /> | ||
| import { Gender, OnlineStatus } from "./common"; | ||
| import { OcrResult } from "./internal"; | ||
| import { StrangerInfo, FriendInfo, GroupInfo, MemberInfo } from "./entities"; | ||
@@ -146,5 +147,7 @@ import { EventMap } from "./events"; | ||
| /** 获取转发消息 */ | ||
| getForwardMsg(resid: string): Promise<import("./message").ForwardMessage[]>; | ||
| getForwardMsg(resid: string, fileName?: string): Promise<import("./message").ForwardMessage[]>; | ||
| /** 制作转发消息 */ | ||
| makeForwardMsg(fake: Forwardable[], dm?: boolean): Promise<import("./message").XmlElem>; | ||
| /** Ocr图片转文字 */ | ||
| imageOcr(file: ImageElem["file"]): Promise<OcrResult>; | ||
| /** @cqhttp (cqhttp遗留方法) use client.cookies[domain] */ | ||
@@ -165,3 +168,3 @@ getCookies(domain?: Domain): string; | ||
| sex: Gender; | ||
| age: number; /** 日志记录器,初始情况下是`log4js.Logger` */ | ||
| age: number; /** 配置 */ | ||
| area: string; | ||
@@ -168,0 +171,0 @@ }>; |
+6
-16
@@ -279,16 +279,2 @@ "use strict"; | ||
| } | ||
| // reloadGuildList() { | ||
| // this.writeUni("trpc.group_pro.synclogic.SyncLogic.SyncFirstView", pb.encode({ 1: 0, 2: 0, 3: 0 })) | ||
| // return new Promise<void>((resolve, reject) => { | ||
| // const id = setTimeout(() => { | ||
| // this.off("internal.loadguilds", tmp) | ||
| // reject() | ||
| // }, 5000) | ||
| // this.once("internal.loadguilds", tmp) | ||
| // function tmp() { | ||
| // clearTimeout(id) | ||
| // resolve() | ||
| // } | ||
| // }) | ||
| // } | ||
| /** 清空缓存文件 fs.rm need v14.14 */ | ||
@@ -306,4 +292,4 @@ cleanCache() { | ||
| /** 获取转发消息 */ | ||
| getForwardMsg(resid) { | ||
| return this.pickFriend(this.uin).getForwardMsg(resid); | ||
| getForwardMsg(resid, fileName) { | ||
| return this.pickFriend(this.uin).getForwardMsg(resid, fileName); | ||
| } | ||
@@ -314,2 +300,6 @@ /** 制作转发消息 */ | ||
| } | ||
| /** Ocr图片转文字 */ | ||
| imageOcr(file) { | ||
| return internal_1.imageOcr.call(this, new message_1.Image({ type: "image", file })); | ||
| } | ||
| /** @cqhttp (cqhttp遗留方法) use client.cookies[domain] */ | ||
@@ -316,0 +306,0 @@ getCookies(domain = "") { |
@@ -122,15 +122,18 @@ /// <reference types="node" /> | ||
| logout(keepalive?: boolean): Promise<void>; | ||
| /** 直接关闭连接 */ | ||
| /** 关闭连接 */ | ||
| terminate(): void; | ||
| /** 使用上报的token登录 */ | ||
| /** 使用接收到的token登录 */ | ||
| tokenLogin(token: Buffer): void; | ||
| /** 使用密码登录 */ | ||
| /** | ||
| * 使用密码登录 | ||
| * @param md5pass 密码的md5值 | ||
| */ | ||
| passwordLogin(md5pass: Buffer): void; | ||
| /** 提交滑动验证码 */ | ||
| /** 收到滑动验证码后,用于提交滑动验证码 */ | ||
| submitSlider(ticket: string): void; | ||
| /** 发短信 */ | ||
| /** 收到设备锁验证请求后,用于发短信 */ | ||
| sendSmsCode(): void; | ||
| /** 提交短信验证码 */ | ||
| submitSmsCode(code: string): void; | ||
| /** 获取登录二维码 */ | ||
| /** 获取登录二维码(模拟手表协议扫码登录) */ | ||
| fetchQrcode(): void; | ||
@@ -137,0 +140,0 @@ /** 扫码后调用此方法登录 */ |
@@ -186,3 +186,3 @@ "use strict"; | ||
| } | ||
| /** 直接关闭连接 */ | ||
| /** 关闭连接 */ | ||
| terminate() { | ||
@@ -192,3 +192,3 @@ this[IS_ONLINE] = false; | ||
| } | ||
| /** 使用上报的token登录 */ | ||
| /** 使用接收到的token登录 */ | ||
| tokenLogin(token) { | ||
@@ -227,3 +227,6 @@ if (![144, 152].includes(token.length)) | ||
| } | ||
| /** 使用密码登录 */ | ||
| /** | ||
| * 使用密码登录 | ||
| * @param md5pass 密码的md5值 | ||
| */ | ||
| passwordLogin(md5pass) { | ||
@@ -264,4 +267,5 @@ this.sig.session = (0, crypto_1.randomBytes)(4); | ||
| } | ||
| /** 提交滑动验证码 */ | ||
| /** 收到滑动验证码后,用于提交滑动验证码 */ | ||
| submitSlider(ticket) { | ||
| ticket = String(ticket).trim(); | ||
| const t = tlv.getPacker(this); | ||
@@ -271,3 +275,3 @@ const body = new writer_1.default() | ||
| .writeU16(4) | ||
| .writeBytes(t(0x193, String(ticket))) | ||
| .writeBytes(t(0x193, ticket)) | ||
| .writeBytes(t(0x8)) | ||
@@ -279,3 +283,3 @@ .writeBytes(t(0x104)) | ||
| } | ||
| /** 发短信 */ | ||
| /** 收到设备锁验证请求后,用于发短信 */ | ||
| sendSmsCode() { | ||
@@ -314,3 +318,3 @@ const t = tlv.getPacker(this); | ||
| } | ||
| /** 获取登录二维码 */ | ||
| /** 获取登录二维码(模拟手表协议扫码登录) */ | ||
| fetchQrcode() { | ||
@@ -941,3 +945,3 @@ const t = tlv.getPacker(this); | ||
| } | ||
| return this.emit("internal.verify", String(t[0x204]), phone); | ||
| return this.emit("internal.verify", t[0x204]?.toString() || "", phone); | ||
| } | ||
@@ -944,0 +948,0 @@ if (t[0x149]) { |
@@ -157,3 +157,3 @@ "use strict"; | ||
| apklist[Platform.iMac].display = "iMac"; | ||
| apklist[Platform.iPad].subid = 537065739; | ||
| apklist[Platform.iPad].subid = 537118796; | ||
| apklist[Platform.iPad].display = "iPad"; | ||
@@ -160,0 +160,0 @@ function getApkInfo(p) { |
+18
-0
@@ -0,1 +1,3 @@ | ||
| /// <reference types="node" /> | ||
| import { pb } from "./core"; | ||
| import { Gender } from "./common"; | ||
@@ -44,2 +46,8 @@ import { Sendable, PrivateMessage, MusicPlatform, Quotable } from "./message"; | ||
| sendMsg(content: Sendable, source?: Quotable): Promise<MessageRet>; | ||
| protected _sendMsg(proto3: pb.Encodable, brief: string, file?: boolean): Promise<{ | ||
| message_id: string; | ||
| seq: number; | ||
| rand: number; | ||
| time: any; | ||
| }>; | ||
| /** 回添双向好友 */ | ||
@@ -80,3 +88,13 @@ addFriendBack(seq: number, remark?: string): Promise<boolean>; | ||
| delete(block?: boolean): Promise<boolean>; | ||
| /** | ||
| * 发送离线文件 | ||
| * @param file 一个文件路径,或者一块Buffer | ||
| * @param filename 对方看到的文件名(file为Buffer时,若留空则自动以md5命名) | ||
| * @param callback 监控上传进度的回调函数,拥有一个"百分比进度"的参数 | ||
| * @returns 文件id(撤回时使用) | ||
| */ | ||
| sendFile(file: string | Buffer, filename?: string, callback?: (percentage: string) => void): Promise<string>; | ||
| /** 撤回离线文件 */ | ||
| recallFile(fid: string): Promise<boolean>; | ||
| } | ||
| export {}; |
+140
-5
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.Friend = exports.User = void 0; | ||
| const crypto_1 = require("crypto"); | ||
| const stream_1 = require("stream"); | ||
| const fs_1 = __importDefault(require("fs")); | ||
| const path_1 = __importDefault(require("path")); | ||
| const core_1 = require("./core"); | ||
@@ -129,3 +135,3 @@ const errors_1 = require("./errors"); | ||
| } | ||
| _getRouting() { | ||
| _getRouting(file = false) { | ||
| if (Reflect.has(this, "gid")) | ||
@@ -136,3 +142,3 @@ return { 3: { | ||
| } }; | ||
| return { 1: { 1: this.uid } }; | ||
| return file ? { 15: { 1: this.uid, 2: 4 } } : { 1: { 1: this.uid } }; | ||
| } | ||
@@ -145,12 +151,14 @@ /** | ||
| const { rich, brief } = await this._preprocess(content, source); | ||
| return this._sendMsg({ 1: rich }, brief); | ||
| } | ||
| async _sendMsg(proto3, brief, file = false) { | ||
| const seq = this.c.sig.seq + 1; | ||
| const rand = (0, crypto_1.randomBytes)(4).readUInt32BE(); | ||
| const body = core_1.pb.encode({ | ||
| 1: this._getRouting(), | ||
| 1: this._getRouting(file), | ||
| 2: common_1.PB_CONTENT, | ||
| 3: { 1: rich }, | ||
| 3: proto3, | ||
| 4: seq, | ||
| 5: rand, | ||
| 6: (0, internal_1.buildSyncCookie)(this.c.sig.session.readUInt32BE()), | ||
| 8: 0 | ||
| }); | ||
@@ -363,3 +371,130 @@ const payload = await this.c.sendUni("MessageSvc.PbSendMsg", body); | ||
| } | ||
| /** | ||
| * 发送离线文件 | ||
| * @param file 一个文件路径,或者一块Buffer | ||
| * @param filename 对方看到的文件名(file为Buffer时,若留空则自动以md5命名) | ||
| * @param callback 监控上传进度的回调函数,拥有一个"百分比进度"的参数 | ||
| * @returns 文件id(撤回时使用) | ||
| */ | ||
| async sendFile(file, filename, callback) { | ||
| let filesize, filemd5, filesha, filestream; | ||
| if (file instanceof Buffer) { | ||
| filesize = file.length; | ||
| filemd5 = (0, common_1.md5)(file), filesha = (0, common_1.sha)(file); | ||
| filename = filename ? String(filename) : ("file" + filemd5.toString("hex")); | ||
| filestream = stream_1.Readable.from(file, { objectMode: false, highWaterMark: 524288 }); | ||
| } | ||
| else { | ||
| file = String(file); | ||
| filesize = (await fs_1.default.promises.stat(file)).size; | ||
| [filemd5, filesha] = await (0, common_1.fileHash)(file); | ||
| filename = filename ? String(filename) : path_1.default.basename(file); | ||
| filestream = fs_1.default.createReadStream(file, { highWaterMark: 524288 }); | ||
| } | ||
| const body1700 = core_1.pb.encode({ | ||
| 1: 1700, | ||
| 2: 6, | ||
| 19: { | ||
| 10: this.c.uin, | ||
| 20: this.uid, | ||
| 30: filesize, | ||
| 40: filename, | ||
| 50: filemd5, | ||
| 60: filesha, | ||
| 70: "/storage/emulated/0/Android/data/com.tencent.mobileqq/Tencent/QQfile_recv/" + filename, | ||
| 80: 0, | ||
| 90: 0, | ||
| 100: 0, | ||
| 110: filemd5, | ||
| }, | ||
| 101: 3, | ||
| 102: 104, | ||
| 200: 1, | ||
| }); | ||
| const payload = await this.c.sendUni("OfflineFilleHandleSvr.pb_ftn_CMD_REQ_APPLY_UPLOAD_V3-1700", body1700); | ||
| const rsp1700 = core_1.pb.decode(payload)[19]; | ||
| const fid = rsp1700[90].toBuffer(); | ||
| const ext = core_1.pb.encode({ | ||
| 1: 100, | ||
| 2: 2, | ||
| 100: { | ||
| 100: { | ||
| 1: 3, | ||
| 100: this.c.uin, | ||
| 200: this.uid, | ||
| 400: 0, | ||
| 700: payload, | ||
| }, | ||
| 200: { | ||
| 100: filesize, | ||
| 200: filemd5, | ||
| 300: filesha, | ||
| 400: filemd5, | ||
| 600: fid, | ||
| 700: rsp1700[220].toBuffer(), | ||
| }, | ||
| 300: { | ||
| 100: 2, | ||
| 200: String(this.c.apk.subid), | ||
| 300: 2, | ||
| 400: "d92615c5", | ||
| 600: 4, | ||
| }, | ||
| 400: { | ||
| 100: filename, | ||
| }, | ||
| }, | ||
| 200: 1 | ||
| }); | ||
| await internal_1.highwayHttpUpload.call(this.c, filestream, { | ||
| md5: filemd5, | ||
| size: filesize, | ||
| cmdid: internal_1.CmdID.OfflineFile, | ||
| ext, callback | ||
| }); | ||
| const body800 = core_1.pb.encode({ | ||
| 1: 800, | ||
| 2: 7, | ||
| 10: { | ||
| 10: this.c.uin, | ||
| 20: this.uid, | ||
| 30: fid, | ||
| }, | ||
| 101: 3, | ||
| 102: 104, | ||
| }); | ||
| await this.c.sendUni("OfflineFilleHandleSvr.pb_ftn_CMD_REQ_UPLOAD_SUCC-800", body800); | ||
| const proto3 = { | ||
| 2: { | ||
| 1: { | ||
| 1: 0, | ||
| 3: fid, | ||
| 4: filemd5, | ||
| 5: filename, | ||
| 6: filesize, | ||
| 9: 1, | ||
| } | ||
| } | ||
| }; | ||
| await this._sendMsg(proto3, `[文件:${filename}]`, true); | ||
| return String(fid); | ||
| } | ||
| /** 撤回离线文件 */ | ||
| async recallFile(fid) { | ||
| const body = core_1.pb.encode({ | ||
| 1: 400, | ||
| 2: 0, | ||
| 6: { | ||
| 1: this.c.uin, | ||
| 2: fid | ||
| }, | ||
| 101: 3, | ||
| 102: 104, | ||
| 200: 1, | ||
| }); | ||
| const payload = await this.c.sendUni("OfflineFilleHandleSvr.pb_ftn_CMD_REQ_RECALL-400", body); | ||
| const rsp = core_1.pb.decode(payload)[6]; | ||
| return rsp[1] === 0; | ||
| } | ||
| } | ||
| exports.Friend = Friend; |
+1
-1
@@ -74,3 +74,3 @@ /// <reference types="node" /> | ||
| * @param pid 上传到此目录(默认根目录) | ||
| * @param name 若留空则自动以md5命名 | ||
| * @param name file为Buffer时,若留空则自动以md5命名 | ||
| * @param callback 监控上传进度的回调函数,拥有一个"百分比进度"的参数 | ||
@@ -77,0 +77,0 @@ */ |
+1
-1
@@ -276,3 +276,3 @@ "use strict"; | ||
| * @param pid 上传到此目录(默认根目录) | ||
| * @param name 若留空则自动以md5命名 | ||
| * @param name file为Buffer时,若留空则自动以md5命名 | ||
| * @param callback 监控上传进度的回调函数,拥有一个"百分比进度"的参数 | ||
@@ -279,0 +279,0 @@ */ |
+1
-0
@@ -13,1 +13,2 @@ export { Client, createClient, Config, Logger, LogLevel, Statistics } from "./client"; | ||
| export * as core from "./core"; | ||
| export { OcrResult } from "./internal"; |
+3
-1
@@ -22,3 +22,3 @@ "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.core = exports.Platform = exports.ApiRejection = exports.segment = exports.getGroupImageUrl = exports.parseImageFileParam = exports.parseGroupMessageId = exports.parseDmMessageId = exports.ForwardMessage = exports.DiscussMessage = exports.GroupMessage = exports.PrivateMessage = exports.Message = exports.LoginErrorCode = exports.ErrorCode = exports.OnlineStatus = exports.Gfs = exports.Member = exports.Group = exports.Discuss = exports.Friend = exports.User = exports.createClient = exports.Client = void 0; | ||
| exports.OcrResult = exports.core = exports.Platform = exports.ApiRejection = exports.segment = exports.getGroupImageUrl = exports.parseImageFileParam = exports.parseGroupMessageId = exports.parseDmMessageId = exports.ForwardMessage = exports.DiscussMessage = exports.GroupMessage = exports.PrivateMessage = exports.Message = exports.LoginErrorCode = exports.ErrorCode = exports.OnlineStatus = exports.Gfs = exports.Member = exports.Group = exports.Discuss = exports.Friend = exports.User = exports.createClient = exports.Client = void 0; | ||
| var client_1 = require("./client"); | ||
@@ -57,1 +57,3 @@ Object.defineProperty(exports, "Client", { enumerable: true, get: function () { return client_1.Client; } }); | ||
| exports.core = __importStar(require("./core")); | ||
| var internal_1 = require("./internal"); | ||
| Object.defineProperty(exports, "OcrResult", { enumerable: true, get: function () { return internal_1.OcrResult; } }); |
@@ -28,6 +28,11 @@ /// <reference types="node" /> | ||
| private _uploadMultiMsg; | ||
| /** 制作一条合并转发消息以备发送(理论上传一次所有群和好友都能发) */ | ||
| makeForwardMsg(iterable: Forwardable[]): Promise<XmlElem>; | ||
| /** | ||
| * 1. 制作一条合并转发消息以备发送(制作一次可以到处发)。 | ||
| * 2. 需要注意的是,好友图片和群图片的内部格式不一样, | ||
| * 对着群制作的转发消息中的图片,发给好友可能会裂图,反过来也一样。 | ||
| * 3. 暂不完全支持套娃转发。 | ||
| */ | ||
| makeForwardMsg(msglist: Forwardable[] | Forwardable): Promise<XmlElem>; | ||
| /** 下载并解析合并转发 */ | ||
| getForwardMsg(resid: string): Promise<ForwardMessage[]>; | ||
| getForwardMsg(resid: string, fileName?: string): Promise<ForwardMessage[]>; | ||
| private _downloadMultiMsg; | ||
@@ -34,0 +39,0 @@ /** 获取视频下载地址 */ |
@@ -399,4 +399,11 @@ "use strict"; | ||
| } | ||
| /** 制作一条合并转发消息以备发送(理论上传一次所有群和好友都能发) */ | ||
| async makeForwardMsg(iterable) { | ||
| /** | ||
| * 1. 制作一条合并转发消息以备发送(制作一次可以到处发)。 | ||
| * 2. 需要注意的是,好友图片和群图片的内部格式不一样, | ||
| * 对着群制作的转发消息中的图片,发给好友可能会裂图,反过来也一样。 | ||
| * 3. 暂不完全支持套娃转发。 | ||
| */ | ||
| async makeForwardMsg(msglist) { | ||
| if (!Array.isArray(msglist)) | ||
| msglist = [msglist]; | ||
| const nodes = []; | ||
@@ -407,3 +414,3 @@ const makers = []; | ||
| let cnt = 0; | ||
| for (const fake of iterable) { | ||
| for (const fake of msglist) { | ||
| const maker = new message_1.Converter(fake.message, { dm: this.dm, cachedir: this.c.config.data_dir }); | ||
@@ -433,3 +440,3 @@ makers.push(maker); | ||
| }, | ||
| 14: nickname, | ||
| 14: this.dm ? nickname : null, | ||
| 20: { | ||
@@ -468,6 +475,15 @@ 1: 0, | ||
| /** 下载并解析合并转发 */ | ||
| async getForwardMsg(resid) { | ||
| async getForwardMsg(resid, fileName = "MultiMsg") { | ||
| const ret = []; | ||
| const buf = await this._downloadMultiMsg(String(resid), 2); | ||
| let a = core_1.pb.decode(buf)[2]; | ||
| if (!Array.isArray(a)) | ||
| a = [a]; | ||
| for (let b of a) { | ||
| const m_fileName = b[1].toString(); | ||
| if (m_fileName === fileName) { | ||
| a = b; | ||
| break; | ||
| } | ||
| } | ||
| if (Array.isArray(a)) | ||
@@ -474,0 +490,0 @@ a = a[0]; |
| /// <reference types="node" /> | ||
| import * as stream from "stream"; | ||
| import { pb } from "../core"; | ||
| declare type Client = import("../client").Client; | ||
@@ -12,3 +13,5 @@ export declare enum CmdID { | ||
| GroupPtt = 29, | ||
| GroupFile = 71 | ||
| OfflineFile = 69, | ||
| GroupFile = 71, | ||
| Ocr = 76 | ||
| } | ||
@@ -27,3 +30,4 @@ /** 上传时的附加数据,必须知道流的size和md5 */ | ||
| /** highway上传数据 (只能上传流) */ | ||
| export declare function highwayUpload(this: Client, readable: stream.Readable, obj: HighwayUploadExt, ip?: string | number, port?: number): Promise<void>; | ||
| export declare function highwayUpload(this: Client, readable: stream.Readable, obj: HighwayUploadExt, ip?: string | number, port?: number): Promise<pb.Proto | void>; | ||
| export declare function highwayHttpUpload(this: Client, readable: stream.Readable, obj: HighwayUploadExt): Promise<unknown>; | ||
| export {}; |
+100
-3
@@ -21,7 +21,11 @@ "use strict"; | ||
| }; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.highwayUpload = exports.CmdID = void 0; | ||
| exports.highwayHttpUpload = exports.highwayUpload = exports.CmdID = void 0; | ||
| const stream = __importStar(require("stream")); | ||
| const net = __importStar(require("net")); | ||
| const crypto_1 = require("crypto"); | ||
| const axios_1 = __importDefault(require("axios")); | ||
| const core_1 = require("../core"); | ||
@@ -39,3 +43,5 @@ const errors_1 = require("../errors"); | ||
| CmdID[CmdID["GroupPtt"] = 29] = "GroupPtt"; | ||
| CmdID[CmdID["OfflineFile"] = 69] = "OfflineFile"; | ||
| CmdID[CmdID["GroupFile"] = 71] = "GroupFile"; | ||
| CmdID[CmdID["Ocr"] = 76] = "Ocr"; | ||
| })(CmdID = exports.CmdID || (exports.CmdID = {})); | ||
@@ -121,3 +127,3 @@ const __ = Buffer.from([41]); | ||
| socket.end(); | ||
| resolve(); | ||
| resolve(rsp[7]); | ||
| } | ||
@@ -136,5 +142,10 @@ } | ||
| } | ||
| else { | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| catch { } | ||
| catch (err) { | ||
| this.logger.error(err); | ||
| } | ||
| }); | ||
@@ -160,1 +171,87 @@ socket.on("close", () => { | ||
| exports.highwayUpload = highwayUpload; | ||
| async function highwayHttpUpload(readable, obj) { | ||
| const ip = this.sig.bigdata.ip; | ||
| const port = this.sig.bigdata.port; | ||
| if (!port) | ||
| throw new core_1.ApiRejection(errors_1.ErrorCode.NoUploadChannel, "没有上传通道,如果你刚刚登录,请等待几秒"); | ||
| this.logger.debug(`highway(http) ip:${ip} port:${port}`); | ||
| const url = "http://" + ip + ":" + port + "/cgi-bin/httpconn?htcmd=0x6FF0087&uin=" + this.uin; | ||
| let seq = 1; | ||
| let offset = 0, limit = 524288; | ||
| obj.ticket = this.sig.bigdata.sig_session; | ||
| const tasks = []; | ||
| let finished = 0; | ||
| readable.on("data", data => { | ||
| let _offset = 0; | ||
| while (_offset < data.length) { | ||
| const chunk = data.slice(_offset, limit + _offset); | ||
| const head = core_1.pb.encode({ | ||
| 1: { | ||
| 1: 1, | ||
| 2: String(this.uin), | ||
| 3: "PicUp.DataUp", | ||
| 4: seq++, | ||
| 5: 0, | ||
| 6: this.apk.subid, | ||
| 8: obj.cmdid, | ||
| }, | ||
| 2: { | ||
| 1: 0, | ||
| 2: obj.size, | ||
| 3: offset + _offset, | ||
| 4: chunk.length, | ||
| 6: obj.ticket, | ||
| 8: (0, common_1.md5)(chunk), | ||
| 9: obj.md5, | ||
| 10: 0, | ||
| 13: 0, | ||
| }, | ||
| 3: obj.ext, | ||
| 4: Date.now() | ||
| }); | ||
| _offset += chunk.length; | ||
| const _ = Buffer.allocUnsafe(9); | ||
| _.writeUInt8(40); | ||
| _.writeUInt32BE(head.length, 1); | ||
| _.writeUInt32BE(chunk.length, 5); | ||
| const buf = Buffer.concat([_, head, chunk, __]); | ||
| const task = new Promise((resolve, reject) => { | ||
| axios_1.default.post(url, buf, { | ||
| responseType: "arraybuffer", | ||
| headers: { | ||
| "Content-Length": String(buf.length) | ||
| } | ||
| }).then(r => { | ||
| let percentage, rsp; | ||
| try { | ||
| const buf = Buffer.from(r?.data); | ||
| const header = buf.slice(9, buf.length - 1); | ||
| rsp = core_1.pb.decode(header); | ||
| } | ||
| catch (err) { | ||
| this.logger.error(err); | ||
| reject(err); | ||
| return; | ||
| } | ||
| if (rsp?.[3] !== 0) { | ||
| reject(new core_1.ApiRejection(rsp[3], "unknown highway error")); | ||
| return; | ||
| } | ||
| ++finished; | ||
| percentage = (finished / tasks.length * 100).toFixed(2); | ||
| this.logger.debug(`highway(http) chunk uploaded (${percentage}%)`); | ||
| if (typeof obj.callback === "function" && percentage) | ||
| obj.callback(percentage); | ||
| resolve(undefined); | ||
| }); | ||
| }); | ||
| tasks.push(task); | ||
| } | ||
| offset += data.length; | ||
| }); | ||
| return new Promise((resolve, reject) => { | ||
| readable.on("err", reject) | ||
| .on("end", () => resolve(Promise.all(tasks))); | ||
| }); | ||
| } | ||
| exports.highwayHttpUpload = highwayHttpUpload; |
@@ -0,1 +1,2 @@ | ||
| import { pb } from "../core"; | ||
| import { OnlineStatus } from "../common"; | ||
@@ -16,2 +17,16 @@ import { Image } from "../message"; | ||
| export declare function loadBL(this: Client): Promise<void>; | ||
| export declare class OcrResult { | ||
| language: string; | ||
| wordslist: Array<{ | ||
| words: string; | ||
| confidence: number; | ||
| polygon: Array<{ | ||
| x: number; | ||
| y: number; | ||
| }>; | ||
| }>; | ||
| constructor(proto: pb.Proto); | ||
| toString(): string; | ||
| } | ||
| export declare function imageOcr(this: Client, img: Image): Promise<OcrResult>; | ||
| export {}; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.loadBL = exports.loadGL = exports.loadSL = exports.loadFL = exports.renameClass = exports.delClass = exports.addClass = exports.delStamp = exports.getStamp = exports.setAvatar = exports.setSign = exports.setStatus = void 0; | ||
| exports.imageOcr = exports.OcrResult = exports.loadBL = exports.loadGL = exports.loadSL = exports.loadFL = exports.renameClass = exports.delClass = exports.addClass = exports.delStamp = exports.getStamp = exports.setAvatar = exports.setSign = exports.setStatus = void 0; | ||
| const core_1 = require("../core"); | ||
@@ -285,1 +285,55 @@ const errors_1 = require("../errors"); | ||
| exports.loadBL = loadBL; | ||
| class OcrResult { | ||
| constructor(proto) { | ||
| this.wordslist = []; | ||
| this.language = proto[2]?.toString() || "unknown"; | ||
| if (!Array.isArray(proto[1])) | ||
| proto[1] = [proto[1]]; | ||
| for (let p of proto[1]) { | ||
| this.wordslist.push({ | ||
| words: p[1]?.toString() || "", | ||
| confidence: Number(p[2]), | ||
| polygon: p[3][1].map((v) => ({ x: Number(v[1]) || 0, y: Number(v[2]) || 0 })), | ||
| }); | ||
| } | ||
| } | ||
| toString() { | ||
| let str = ""; | ||
| for (const elem of this.wordslist) | ||
| str += elem.words; | ||
| return str; | ||
| } | ||
| } | ||
| exports.OcrResult = OcrResult; | ||
| async function imageOcr(img) { | ||
| await img.task; | ||
| const url = String((await highway_1.highwayUpload.call(this, img.readable, { | ||
| cmdid: highway_1.CmdID.Ocr, | ||
| md5: img.md5, | ||
| size: img.size, | ||
| ext: core_1.pb.encode({ | ||
| 1: 0, | ||
| 2: (0, common_1.uuid)(), | ||
| }) | ||
| }))?.[2]); | ||
| const body = core_1.pb.encode({ | ||
| 1: 1, | ||
| 2: 0, | ||
| 3: 1, | ||
| 10: { | ||
| 1: url, | ||
| 10: img.md5.toString("hex"), | ||
| 11: img.md5.toString("hex"), | ||
| 12: img.size, | ||
| 13: img.width, | ||
| 14: img.height, | ||
| 15: 0, | ||
| } | ||
| }); | ||
| const payload = await this.sendOidb("OidbSvc.0xe07_0", body, 10); | ||
| const rsp = core_1.pb.decode(payload); | ||
| if (rsp[3] !== 0) | ||
| (0, errors_1.drop)(rsp[3], rsp[5]); | ||
| return new OcrResult(rsp[4][10]); | ||
| } | ||
| exports.imageOcr = imageOcr; |
@@ -184,3 +184,3 @@ /// <reference types="node" /> | ||
| */ | ||
| at(qq: number | string, text?: string | undefined, dummy?: boolean | undefined): AtElem; | ||
| at(qq: number | "all" | string, text?: string | undefined, dummy?: boolean | undefined): AtElem; | ||
| /** 图片(支持http://,base64://) */ | ||
@@ -187,0 +187,0 @@ image(file: ImageElem["file"], cache?: boolean | undefined, timeout?: number | undefined, headers?: import("http").OutgoingHttpHeaders | undefined): ImageElem; |
@@ -46,5 +46,5 @@ "use strict"; | ||
| at(qq, text, dummy) { | ||
| if (Number(qq) <= 0xffffffff || qq === "all") { | ||
| if (typeof qq === "number" || qq === "all") { | ||
| return { | ||
| type: "at", qq: Number(qq), text, dummy | ||
| type: "at", qq, text, dummy | ||
| }; | ||
@@ -51,0 +51,0 @@ } |
@@ -170,3 +170,2 @@ "use strict"; | ||
| headers, | ||
| maxRedirects: 3, | ||
| responseType: "stream", | ||
@@ -173,0 +172,0 @@ })).data; |
@@ -155,2 +155,3 @@ /// <reference types="node" /> | ||
| nickname: string; | ||
| group_id?: number; | ||
| time: number; | ||
@@ -157,0 +158,0 @@ message: MessageElem[]; |
@@ -180,2 +180,4 @@ "use strict"; | ||
| const trans = body[2][1]; | ||
| if (trans[1] !== 0) | ||
| throw new Error("unsupported message (ignore ok)"); | ||
| const elem = { | ||
@@ -310,2 +312,3 @@ type: "file", | ||
| this.nickname = head[14]?.toString() || head[9]?.[4]?.toString() || ""; | ||
| this.group_id = head[9]?.[1]; | ||
| this.parsed = (0, parser_1.parse)(proto[3][1]); | ||
@@ -312,0 +315,0 @@ this.message = this.parsed.message; |
+2
-2
| { | ||
| "name": "oicq", | ||
| "version": "2.2.3", | ||
| "upday": "2021/5/17", | ||
| "version": "2.3.0", | ||
| "upday": "2022/6/19", | ||
| "description": "QQ protocol!", | ||
@@ -6,0 +6,0 @@ "main": "lib/index.js", |
+3
-0
@@ -96,2 +96,3 @@ # oicq | ||
| | getVideoUrl() | 获取视频地址 | | ||
| | imageOcr() | ocr | | ||
| | cleanCache() | 清空缓存文件 | | ||
@@ -238,2 +239,4 @@ | ||
| | delete() | 删除 | | ||
| | sendFile() | 发送文件 | | ||
| | recallFile() | 撤回文件 | | ||
@@ -240,0 +243,0 @@ | Property | Description | |
AI-detected potential malware
Supply chain riskAI has identified this package as malware. This is a strong signal that the package may be malicious.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
552776
2.41%13873
2.59%396
0.76%1
Infinity%11
10%