diff --git a/src/common/config.ts b/src/common/config.ts index b6e1f4c..97988d3 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -82,12 +82,9 @@ export class ConfigUtil { fs.writeFileSync(this.configPath, JSON.stringify(config, null, 2), 'utf-8') } - private checkOldConfig( - currentConfig: Config | OB11Config, - oldConfig: Config | OB11Config, - currentKey: string, - oldKey: string, - ) { + private checkOldConfig(currentConfig: Config | OB11Config, + oldConfig: Config | OB11Config, + currentKey: string, oldKey: string) { // 迁移旧的配置到新配置,避免用户重新填写配置 const oldValue = oldConfig[oldKey] if (oldValue) { diff --git a/src/common/types.ts b/src/common/types.ts index 82e3a32..b0a3b90 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -12,11 +12,10 @@ export interface OB11Config { enableHttpHeart?: boolean } export interface CheckVersion { - result: boolean + result: boolean, version: string } export interface Config { - imageRKey?: string ob11: OB11Config token?: string heartInterval?: number // ms @@ -29,6 +28,7 @@ export interface Config { ffmpeg?: string // ffmpeg路径 enablePoke?: boolean musicSignUrl?: string + ignoreBeforeLoginMsg?: boolean } export interface LLOneBotError { diff --git a/src/ntqqapi/api/file.ts b/src/ntqqapi/api/file.ts index a366839..b54527c 100644 --- a/src/ntqqapi/api/file.ts +++ b/src/ntqqapi/api/file.ts @@ -7,30 +7,26 @@ import { ChatCacheList, ChatCacheListItemBasic, ChatType, - ElementType, - IMAGE_HTTP_HOST, - IMAGE_HTTP_HOST_NT, - RawMessage, + ElementType, IMAGE_HTTP_HOST, IMAGE_HTTP_HOST_NT, RawMessage, } from '../types' import path from 'path' import fs from 'fs' import { ReceiveCmdS } from '../hook' import { log } from '../../common/utils' -import http from 'http' +import https from 'https' import { sleep } from '../../common/utils' import { hookApi } from '../external/moehook/hook' let privateImageRKey = '' let groupImageRKey = '' -let lastGetRKeyTime = 0 +let lastGetPrivateRKeyTime = 0 +let lastGetGroupRKeyTime = 0 const rkeyExpireTime = 1000 * 60 * 30 export class NTQQFileApi { static async getFileType(filePath: string) { return await callNTQQApi<{ ext: string }>({ - className: NTQQApiClass.FS_API, - methodName: NTQQApiMethod.FILE_TYPE, - args: [filePath], + className: NTQQApiClass.FS_API, methodName: NTQQApiMethod.FILE_TYPE, args: [filePath], }) } @@ -46,20 +42,16 @@ export class NTQQFileApi { return await callNTQQApi({ className: NTQQApiClass.FS_API, methodName: NTQQApiMethod.FILE_COPY, - args: [ - { - fromPath: filePath, - toPath: destPath, - }, - ], + args: [{ + fromPath: filePath, + toPath: destPath, + }], }) } static async getFileSize(filePath: string) { return await callNTQQApi({ - className: NTQQApiClass.FS_API, - methodName: NTQQApiMethod.FILE_SIZE, - args: [filePath], + className: NTQQApiClass.FS_API, methodName: NTQQApiMethod.FILE_SIZE, args: [filePath], }) } @@ -78,20 +70,18 @@ export class NTQQFileApi { } const mediaPath = await callNTQQApi({ methodName: NTQQApiMethod.MEDIA_FILE_PATH, - args: [ - { - path_info: { - md5HexStr: md5, - fileName: fileName, - elementType: elementType, - elementSubType, - thumbSize: 0, - needCreate: true, - downloadType: 1, - file_uuid: '', - }, + args: [{ + path_info: { + md5HexStr: md5, + fileName: fileName, + elementType: elementType, + elementSubType, + thumbSize: 0, + needCreate: true, + downloadType: 1, + file_uuid: '', }, - ], + }], }) log('media path', mediaPath) await NTQQFileApi.copyFile(filePath, mediaPath) @@ -105,15 +95,7 @@ export class NTQQFileApi { } } - static async downloadMedia( - msgId: string, - chatType: ChatType, - peerUid: string, - elementId: string, - thumbPath: string, - sourcePath: string, - force: boolean = false, - ) { + static async downloadMedia(msgId: string, chatType: ChatType, peerUid: string, elementId: string, thumbPath: string, sourcePath: string, force: boolean = false) { // 用于下载收到的消息中的图片等 if (sourcePath && fs.existsSync(sourcePath)) { if (force) { @@ -144,7 +126,7 @@ export class NTQQFileApi { methodName: NTQQApiMethod.DOWNLOAD_MEDIA, args: apiParams, cbCmd: ReceiveCmdS.MEDIA_DOWNLOAD_COMPLETE, - cmdCB: (payload: { notifyInfo: { filePath: string; msgId: string } }) => { + cmdCB: (payload: { notifyInfo: { filePath: string, msgId: string } }) => { log('media 下载完成判断', payload.notifyInfo.msgId, msgId) return payload.notifyInfo.msgId == msgId }, @@ -153,20 +135,18 @@ export class NTQQFileApi { } static async getImageSize(filePath: string) { - return await callNTQQApi<{ width: number; height: number }>({ - className: NTQQApiClass.FS_API, - methodName: NTQQApiMethod.IMAGE_SIZE, - args: [filePath], + return await callNTQQApi<{ width: number, height: number }>({ + className: NTQQApiClass.FS_API, methodName: NTQQApiMethod.IMAGE_SIZE, args: [filePath], }) } static async getImageUrl(msg: RawMessage) { const isPrivateImage = msg.chatType !== ChatType.group - const msgElement = msg.elements.find((e) => !!e.picElement) + const msgElement = msg.elements.find(e => !!e.picElement) if (!msgElement) { return '' } - const url = msgElement.picElement.originImageUrl // 没有域名 + const url = msgElement.picElement.originImageUrl // 没有域名 const md5HexStr = msgElement.picElement.md5HexStr const fileMd5 = msgElement.picElement.md5HexStr const fileUuid = msgElement.picElement.fileUuid @@ -185,42 +165,55 @@ export class NTQQFileApi { const saveRKey = (rkey: string) => { if (isPrivateImage) { privateImageRKey = rkey + lastGetPrivateRKeyTime = Date.now() } else { groupImageRKey = rkey + lastGetGroupRKeyTime = Date.now() } - lastGetRKeyTime = Date.now() } const refreshRKey = async () => { log('获取图片rkey...') - NTQQFileApi.downloadMedia( - msg.msgId, - msg.chatType, - msg.peerUid, - msgElement.elementId, - '', - msgElement.picElement.sourcePath, - true, - ) - .then() - .catch(() => {}) + NTQQFileApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, msgElement.elementId, '', msgElement.picElement.sourcePath, false).then().catch(() => { + }) await sleep(1000) const _rkey = hookApi.getRKey() if (_rkey) { - log('图片rkey获取成功', _rkey) - saveRKey(_rkey) - return _rkey + const imageUrl = IMAGE_HTTP_HOST_NT + url + _rkey + // 验证_rkey是否有效 + try { + await new Promise((res, rej) => { + https.get(imageUrl, response => { + if (response.statusCode !== 200) { + rej('图片rkey获取失败') + } else { + res(response) + } + }).on('error', e => { + rej(e) + }) + }) + log('图片rkey获取成功', _rkey) + saveRKey(_rkey) + return _rkey + }catch (e) { + log('图片rkey有误', imageUrl) + } } } const existsRKey = isPrivateImage ? privateImageRKey : groupImageRKey - if (Date.now() - lastGetRKeyTime > rkeyExpireTime || !existsRKey) { + const lastGetRKeyTime = isPrivateImage ? lastGetPrivateRKeyTime : lastGetGroupRKeyTime + if ((Date.now() - lastGetRKeyTime > rkeyExpireTime)) { // rkey过期 const newRKey = await refreshRKey() if (newRKey) { return IMAGE_HTTP_HOST_NT + url + `${newRKey}` } else { log('图片rkey获取失败', url) + if(existsRKey){ + return IMAGE_HTTP_HOST_NT + url + `${existsRKey}` + } return '' } } @@ -239,55 +232,44 @@ export class NTQQFileApi { log('图片url获取失败', msg) return '' } + } export class NTQQFileCacheApi { static async setCacheSilentScan(isSilent: boolean = true) { return await callNTQQApi({ methodName: NTQQApiMethod.CACHE_SET_SILENCE, - args: [ - { - isSilent, - }, - null, - ], + args: [{ + isSilent, + }, null], }) } static getCacheSessionPathList() { - return callNTQQApi< - { - key: string - value: string - }[] - >({ + return callNTQQApi<{ + key: string, + value: string + }[]>({ className: NTQQApiClass.OS_API, methodName: NTQQApiMethod.CACHE_PATH_SESSION, }) } static clearCache(cacheKeys: Array = ['tmp', 'hotUpdate']) { - return callNTQQApi({ - // TODO: 目前还不知道真正的返回值是什么 + return callNTQQApi({ // TODO: 目前还不知道真正的返回值是什么 methodName: NTQQApiMethod.CACHE_CLEAR, - args: [ - { - keys: cacheKeys, - }, - null, - ], + args: [{ + keys: cacheKeys, + }, null], }) } static addCacheScannedPaths(pathMap: object = {}) { return callNTQQApi({ methodName: NTQQApiMethod.CACHE_ADD_SCANNED_PATH, - args: [ - { - pathMap: { ...pathMap }, - }, - null, - ], + args: [{ + pathMap: { ...pathMap }, + }, null], }) } @@ -321,18 +303,14 @@ export class NTQQFileCacheApi { return new Promise((res, rej) => { callNTQQApi({ methodName: NTQQApiMethod.CACHE_CHAT_GET, - args: [ - { - chatType: type, - pageSize, - order: 1, - pageIndex, - }, - null, - ], - }) - .then((list) => res(list)) - .catch((e) => rej(e)) + args: [{ + chatType: type, + pageSize, + order: 1, + pageIndex, + }, null], + }).then(list => res(list)) + .catch(e => rej(e)) }) } @@ -341,29 +319,24 @@ export class NTQQFileCacheApi { return callNTQQApi({ methodName: NTQQApiMethod.CACHE_FILE_GET, - args: [ - { - fileType: fileType, - restart: true, - pageSize: pageSize, - order: 1, - lastRecord: _lastRecord, - }, - null, - ], + args: [{ + fileType: fileType, + restart: true, + pageSize: pageSize, + order: 1, + lastRecord: _lastRecord, + }, null], }) } static async clearChatCache(chats: ChatCacheListItemBasic[] = [], fileKeys: string[] = []) { return await callNTQQApi({ methodName: NTQQApiMethod.CACHE_CHAT_CLEAR, - args: [ - { - chats, - fileKeys, - }, - null, - ], + args: [{ + chats, + fileKeys, + }, null], }) } + } diff --git a/test/check_image_url.js b/test/check_image_url.js new file mode 100644 index 0000000..7a2a386 --- /dev/null +++ b/test/check_image_url.js @@ -0,0 +1,12 @@ +import http from 'https' + +function checkUrl(imageUrl) { + http.get(imageUrl, response => { + console.log(response.statusCode) + }).on('error', e => { + console.log(e) + }) +} + +checkUrl('https://gchat.qpic.cn/download?appid=1407&fileid=CgoxMzMyNTI0MjIxEhRrdaUgQP5MjweWa4uR8pviUDaGQhjcxQUg_wooiYTj39fphQNQgL2jAQ&spec=0&rkey=CAQSKAB6JWENi5LMk0kc62l8Pm3Jn1dsLZHyRLAnNmHGoZ3y_gDZPqZt-64') +checkUrl('https://multimedia.nt.qq.com.cn/download?appid=1407&fileid=CgoxMzMyNTI0MjIxEhRrdaUgQP5MjweWa4uR8pviUDaGQhjcxQUg_wooiYTj39fphQNQgL2jAQ&spec=0&rkey=CAQSKAB6JWENi5LMk0kc62l8Pm3Jn1dsLZHyRLAnNmHGoZ3y_gDZPqZt-64')