-
-
Notifications
You must be signed in to change notification settings - Fork 22
/
imgDownloader.js
145 lines (136 loc) · 4.38 KB
/
imgDownloader.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//大部分摘自LLOneBot
const { RkeyManager } = require("./rkeyManager.js");
const http = require("http");
const https = require("https");
const fs = require("fs");
const path = require("path");
const IMAGE_HTTP_HOST = "https://gchat.qpic.cn";
const IMAGE_HTTP_HOST_NT = "https://multimedia.nt.qq.com.cn";
class ImgDownloader {
constructor() {
this.rkeyManager = new RkeyManager("https://llob.linyuchen.net/rkey");
}
async getImageUrl(element) {
if (!element) {
return "";
}
const url = element.originImageUrl; // 没有域名
const md5HexStr = 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 (md5HexStr) {
// 没有url,需要自己拼接
return `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${md5HexStr.toUpperCase()}/0`;
}
this.output("Pic url get error:", element);
return "";
}
// 下载被撤回的图片(抄自Lite-Tools)
async downloadPic(msgItem) {
if (!Array.isArray(msgItem?.elements)){
return;
}
for (let el of msgItem.elements){
if (el?.picElement) {
const pic = el.picElement;
const thumbMap = new Map([
[
0,
pic.sourcePath,
],
[
198,
pic.sourcePath,
],
[
720,
pic.sourcePath,
],
]);
const picUrl = await this.getImageUrl(el.picElement);
this.output(
"Download lost pic(s)... url=",
picUrl,
"msgId=",
msgItem.msgId,
"to=",
pic.sourcePath
);
let pictureRequireDownload = false;
try{
pictureRequireDownload = statSync(pic.sourcePath).size <= 100;//错误的图片
}catch (e) {
}
if (!fs.existsSync(pic.sourcePath) || pictureRequireDownload) {
this.output("Download pic:", `${picUrl}`, " to ", pic.sourcePath);
const body = await this.request(`${picUrl}`);
try {
JSON.parse(body);
this.output('Picture already expired.', picUrl, pic.sourcePath);//过期
} catch (e) {
fs.mkdirSync(path.dirname(pic.sourcePath), { recursive: true });
fs.writeFileSync(pic.sourcePath, body);
}
} else {
this.output("Pic already existed, skip.", pic.sourcePath);
}
//需要复制原图到预览图目录
// thumbMap.forEach(async (el, key) => {
// if (!fs.existsSync(el)) {
// this.output("Copy thumbs:", `source: ${pic.sourcePath} to ${el}`);
// fs.copyFile(pic.sourcePath, el);
// }
// });
// 修复本地数据中的错误
if (
pic?.thumbPath &&
(pic.thumbPath instanceof Array || pic.thumbPath instanceof Object)
) {
pic.thumbPath = thumbMap;
}
}
}
}
async request(url) {
return new Promise((resolve, reject) => {
const protocol = url.startsWith("https") ? https : http;
const req = protocol.get(url);
req.on("error", (error) => {
this.output("Download error", error);
reject(error);
});
req.on("response", (res) => {
// 发生跳转就继续请求
if (res.statusCode >= 300 && res.statusCode <= 399) {
return resolve(this.request(res.headers.location));
}
const chunks = [];
res.on("error", (error) => {
this.output("Download error", error);
reject(error);
});
res.on("data", (chunk) => chunks.push(chunk));
res.on("end", () => resolve(Buffer.concat(chunks)));
});
});
}
output(...args) {
console.log("\x1b[32m%s\x1b[0m", "Anti-Recall:", ...args);
}
}
module.exports.ImgDownloader = ImgDownloader;