Files
netdisk-fast-download/parser/src/main/java/cn/qaiu/parser/impl/QQTool.java
T
yukaidi af723aed3a fix: NPE 修复、资源泄漏修复及其他 Bug 修复
- 修复 12 处 NPE 风险: FjTool/FsTool/IzTool/LzTool/MkwTool/P115Tool/PdbTool/QQTool/ParserCreate/CommonUtils/ShareLinkInfo/URLParamUtil
- 修复 4 处 Vert.x 资源泄漏: 测试类中 Vertx 实例未关闭
- 修复 CacheManager 防重入和 registerPeriodicCleanup 就绪检查
- 修复 ParserApi 中 redirectUrl()/viewUrl() Promise 未 complete
- 修复 CacheManager.updateTotalByField Promise 永不完成
- 修复 AppMain ShutdownHook 注册,确保 Vert.x 先于 JDBCPoolInit 关闭
- 修复 RouterHandlerFactory failureHandler 恢复返回 failure message
- 修复 ParserCreate/LzTool 收窄 catch 异常类型
- 修复 IzTool/FjTool/IzToolWithAuth 并发安全 (volatile + header 副本)
- 修复 P115Tool UA 为 null 时的 NPE,添加默认 User-Agent
- Font Awesome CDN 换源为 s4.zstatic.net,避免 bootcdn 投毒风险
- DirectoryTree selectAll 补 parserUrl 检查,Home 组件名 App→Home
2026-05-29 14:22:40 +08:00

93 lines
3.7 KiB
Java

package cn.qaiu.parser.impl;
import cn.qaiu.entity.ShareLinkInfo;
import cn.qaiu.parser.PanBase;
import cn.qaiu.util.StringUtils;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.vertx.core.Future;
import io.vertx.core.MultiMap;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
/**
* <a href="https://wx.mail.qq.com/">QQ邮箱</a>
*/
public class QQTool extends PanBase {
public static final String REDIRECT_URL_TEMP = "https://iwx.mail.qq.com/ftn/download?func=4&key={key}&code={code}";
public QQTool(ShareLinkInfo shareLinkInfo) {
super(shareLinkInfo);
}
public Future<String> parse() {
// QQ mail 直接替换为302链接 无需请求
QueryStringDecoder queryStringDecoder = new QueryStringDecoder(shareLinkInfo.getShareUrl(), StandardCharsets.UTF_8);
Map<String, List<String>> prms = queryStringDecoder.parameters();
if (prms.containsKey("key") && prms.containsKey("code") && prms.containsKey("func")) {
log.info(prms.get("func").get(0));
promise.complete(REDIRECT_URL_TEMP.replace("{key}",
prms.get("key").get(0)).replace("{code}", prms.get("code").get(0)));
} else {
fail("key 不合法");
}
// 通过请求URL获取文件信息和直链 暂时不需要
// getFileInfo(key);
return promise.future();
}
private void getFileInfo(String key) {
// 设置基础HTTP头部
var userAgent2 = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, " +
"like " +
"Gecko) Chrome/111.0.0.0 Mobile Safari/537.36";
MultiMap headers = MultiMap.caseInsensitiveMultiMap();
headers.set("User-Agent", userAgent2);
headers.set("sec-ch-ua-platform", "Android");
headers.set("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
headers.set("sec-ch-ua-mobile", "sec-ch-ua-mobile");
// 获取下载中转站页面
client.getAbs(key).putHeaders(headers).send().onSuccess(res -> {
if (res.statusCode() == 200) {
String html = res.bodyAsString();
// 匹配文件信息
String filename = StringUtils.StringCutNot(html, "var filename = \"", "\"");
String filesize = StringUtils.StringCutNot(html, "var filesize = ", "\n");
String fileurl = StringUtils.StringCutNot(html, "var url = \"", "\"");
if (filename != null && filesize != null && fileurl != null) {
// 设置所需HTTP头部
headers.set("Referer", "https://" + StringUtils.StringCutNot(key, "https://", "/") + "/");
headers.set("Host", StringUtils.StringCutNot(fileurl, "https://", "/"));
res.headers().forEach((k, v) -> {
if (k.equalsIgnoreCase("set-cookie")) {
headers.set("Cookie", "mail5k=" + StringUtils.StringCutNot(v, "mail5k=", ";") + ";");
}
});
// 调试匹配的情况
log.debug("文件名称: {}", filename);
log.debug("文件大小: {}", filesize);
log.debug("文件直链: {}", fileurl);
// 提交
promise.complete(fileurl.replace("\\x26", "&"));
} else {
this.fail("匹配失败,可能是分享链接的方式已更新");
}
} else {
this.fail("HTTP状态不正确,可能是分享链接的方式已更新");
}
}).onFailure(this.handleFail(key));
}
}