We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
QQNT版本:9.9.15-27597 (32位)
在开启LiteLoaderQQNT-Anti-Recall插件后,我发现如果被撤回的消息未在QQ窗口中显示,则无法查看被撤回的图片,且图片显示为图裂的标志。
最初,我的想法是将QQ窗口保持在前台,并打开需要监控的群聊窗口以防止消息被撤回。然而,这种方法只能监控一个聊天窗口。
其背后的机制是,QQ仅会自动下载用户在打开窗口时可见的图片消息,而不是随时都下载并保存(这一设计实际上很合理,有助于减轻QQ系统的压力和用户的流量消耗)。
这个机制导致了问题的出现:如果窗口不可见,撤回的图片无法被自动下载和保存。(这是表象,实际上是图片下载的url有变所造成)
为了解决这个问题,首先我们需要找到防撤回功能的源码部分,看看其实现方式:
// 下载被撤回的图片(抄自Lite-Tools) async function processPic(msgItem) { msgItem?.elements?.forEach(async (el) => { if (el?.picElement) { output(el.originImageUrl); output(el); const pic = el.picElement; const picName = pic.md5HexStr.toUpperCase(); const picUrl = `https://gchat.qpic.cn/gchatpic_new/0/0-0-${picName}/`; output("Download lost pic(s)... url=", picUrl, "msgId=", msgItem.msgId); if (!fs.existsSync(pic.sourcePath)) { output("Download pic:", `${picUrl}0`); const body = await request(`${picUrl}0`); fs.mkdirSync(path.dirname(pic.sourcePath), { recursive: true }); fs.writeFileSync(pic.sourcePath, body); } else { output("Pic already existed, skip.", pic.sourcePath); }
从代码中可以看出,程序通过拼接图片的MD5值,向gchat.qpic.cn域名发起请求来下载图片。
gchat.qpic.cn
不过,当我手动使用curl访问这个地址时,收到的返回结果是HTTP ERROR 400。通过Bing查询相关资料,得知该域名广泛用于图片下载,只需知道图片的MD5即可访问。可能由于滥用问题,腾讯已经弃用了这一接口。
curl
HTTP ERROR 400
我还找到一篇相关问题的issue: [BUG] bot自身发出的图片url是无法访问的QQ旧图床链接 #343 LLOneBot/LLOneBot#343
接下来,看看LLOneBot的代码是如何实现的:
export const IMAGE_HTTP_HOST = 'https://gchat.qpic.cn' export const IMAGE_HTTP_HOST_NT = 'https://multimedia.nt.qq.com.cn' async getImageUrl(element: PicElement) { if (!element) { return '' } const url: string = element.originImageUrl! // 没有域名 const md5HexStr = element.md5HexStr const fileMd5 = element.md5HexStr if (url) { const parsedUrl = new URL(IMAGE_HTTP_HOST + url) //临时解析拼接 const imageAppid = parsedUrl.searchParams.get('appid') const isNewPic = imageAppid && ['1406', '1407'].includes(imageAppid) if (isNewPic) { let rkey = parsedUrl.searchParams.get('rkey') if (rkey) { return IMAGE_HTTP_HOST_NT + url } const rkeyData = await this.rkeyManager.getRkey() rkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey return IMAGE_HTTP_HOST_NT + url + rkey } else { // 老的图片url,不需要rkey return IMAGE_HTTP_HOST + url } } else if (fileMd5 || md5HexStr) { // 没有url,需要自己拼接 return `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${(fileMd5 || md5HexStr)!.toUpperCase()}/0` } this.ctx.logger.error('图片url获取失败', element) return '' } }
可以看到,这里的isNewPic部分负责判断是否使用新的图片下载逻辑。
isNewPic
开启调试模式以查看日志:QQ.exe --enable-logging
QQ.exe --enable-logging
打印el对象,修改代码:
el
// 下载被撤回的图片(源自Lite-Tools) async function processPic(msgItem) { msgItem?.elements?.forEach(async (el) => { if (el?.picElement) { output(el.originImageUrl); output(el);
日志显示:
originImageMd5: '40B2CA803B2436E588C19DFCFF5C6C84', originImageUrl: '/download?appid=1406&fileid=Cgk3OTkyNzcyOTESFPoVq_-vLoRr98fH6xLbp2hP6I3cGNbVCCD-Cij9jdSJ-7mIAw&spec=0',
其中,appid=1406与前文的isNewPic判断相符,意味着需要使用新的图片下载逻辑。
appid=1406
我们现在已经知道新的图片下载URL格式是:IMAGE_HTTP_HOST_NT + originImageUrl + rkey
IMAGE_HTTP_HOST_NT + originImageUrl + rkey
rkey可以通过以下地址获取:https://llob.linyuchen.net/rkey,使用private_rkey
rkey
https://llob.linyuchen.net/rkey
private_rkey
示例返回结果:
{ "private_rkey": "&rkey=CAQSKAB6JWENi5LMM1551AAp6a_Ykh9RvPEkj7Vs91WuPERKpLK8jUYK-qE", "group_rkey": "&rkey=CAQSKAB6JWENi5LMM1551AAp6a_Ykh9RvPEkj7Vs91WuPERKNCyRF4OUoU8", "expired_time": 1726030493, "updated_time": "2024-09-11 12:04:53" }
访问该链接后,可以成功下载图片: https://multimedia.nt.qq.com.cn/download?appid=1406&fileid=Cgk3OTkyNzcyOTESFPoVq_-vLoRr98fH6xLbp2hP6I3cGNbVCCD-Cij9jdSJ-7mIAw&spec=0&rkey=CAQSKAB6JWENi5LMM1551AAp6a_Ykh9RvPEkj7Vs91WuPERKpLK8jUYK-qE
https://multimedia.nt.qq.com.cn/download?appid=1406&fileid=Cgk3OTkyNzcyOTESFPoVq_-vLoRr98fH6xLbp2hP6I3cGNbVCCD-Cij9jdSJ-7mIAw&spec=0&rkey=CAQSKAB6JWENi5LMM1551AAp6a_Ykh9RvPEkj7Vs91WuPERKpLK8jUYK-qE
现在只剩下代码实现的工作了,交给作者!我先去吃饭了~~嘿嘿
The text was updated successfully, but these errors were encountered:
非常感谢,我有空就写写~
Sorry, something went wrong.
基本修复了,等下个版本就ok啦
No branches or pull requests
QQNT版本:9.9.15-27597 (32位)
在开启LiteLoaderQQNT-Anti-Recall插件后,我发现如果被撤回的消息未在QQ窗口中显示,则无法查看被撤回的图片,且图片显示为图裂的标志。
![image](https://private-user-images.githubusercontent.com/120435195/366304082-516df1ce-087e-467c-9eda-160ad4a09c30.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk2Mjg2NjEsIm5iZiI6MTczOTYyODM2MSwicGF0aCI6Ii8xMjA0MzUxOTUvMzY2MzA0MDgyLTUxNmRmMWNlLTA4N2UtNDY3Yy05ZWRhLTE2MGFkNGEwOWMzMC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjUwMjE1JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI1MDIxNVQxNDA2MDFaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT0zMjlmMDc4M2Y3YjFjNDg1NzRhNTQ3YTMzZDljYjk1NThiOTEyOTE3ZmU2NDIzM2Q2ZWJhNjIwZjUzYjBjYjVlJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.gigRhtrXAht-agdsu20RyaUYRbiv80Gq0AwmTBjMLzk)
最初,我的想法是将QQ窗口保持在前台,并打开需要监控的群聊窗口以防止消息被撤回。然而,这种方法只能监控一个聊天窗口。
其背后的机制是,QQ仅会自动下载用户在打开窗口时可见的图片消息,而不是随时都下载并保存(这一设计实际上很合理,有助于减轻QQ系统的压力和用户的流量消耗)。
这个机制导致了问题的出现:如果窗口不可见,撤回的图片无法被自动下载和保存。(这是表象,实际上是图片下载的url有变所造成)
问题分析
为了解决这个问题,首先我们需要找到防撤回功能的源码部分,看看其实现方式:
从代码中可以看出,程序通过拼接图片的MD5值,向
gchat.qpic.cn
域名发起请求来下载图片。不过,当我手动使用
curl
访问这个地址时,收到的返回结果是HTTP ERROR 400
。通过Bing查询相关资料,得知该域名广泛用于图片下载,只需知道图片的MD5即可访问。可能由于滥用问题,腾讯已经弃用了这一接口。我还找到一篇相关问题的issue:
[BUG] bot自身发出的图片url是无法访问的QQ旧图床链接 #343
LLOneBot/LLOneBot#343
接下来,看看LLOneBot的代码是如何实现的:
可以看到,这里的
isNewPic
部分负责判断是否使用新的图片下载逻辑。调试过程
开启调试模式以查看日志:
QQ.exe --enable-logging
打印
el
对象,修改代码:日志显示:
其中,
appid=1406
与前文的isNewPic
判断相符,意味着需要使用新的图片下载逻辑。我们现在已经知道新的图片下载URL格式是:
IMAGE_HTTP_HOST_NT + originImageUrl + rkey
获取rkey
rkey
可以通过以下地址获取:https://llob.linyuchen.net/rkey
,使用private_rkey
示例返回结果:
通过新的url下载图片
访问该链接后,可以成功下载图片:
![image](https://private-user-images.githubusercontent.com/120435195/366302292-b2614e74-3384-4b4d-91a5-91cf26a34471.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk2Mjg2NjEsIm5iZiI6MTczOTYyODM2MSwicGF0aCI6Ii8xMjA0MzUxOTUvMzY2MzAyMjkyLWIyNjE0ZTc0LTMzODQtNGI0ZC05MWE1LTkxY2YyNmEzNDQ3MS5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjUwMjE1JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI1MDIxNVQxNDA2MDFaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT0zMjNmYzY2N2E2NTIzYjI0MGFjYTAyMzg3YmE4MjI3YWEzYWM0NGM4NjU2NzNkNzAxNDVjOTVhZDkxMWE5MmY3JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.F_UL_KhPifLlAderuaOPKeIakHKlTVwPzujO6T2XqSY)
https://multimedia.nt.qq.com.cn/download?appid=1406&fileid=Cgk3OTkyNzcyOTESFPoVq_-vLoRr98fH6xLbp2hP6I3cGNbVCCD-Cij9jdSJ-7mIAw&spec=0&rkey=CAQSKAB6JWENi5LMM1551AAp6a_Ykh9RvPEkj7Vs91WuPERKpLK8jUYK-qE
现在只剩下代码实现的工作了,交给作者!我先去吃饭了~~嘿嘿
The text was updated successfully, but these errors were encountered: