mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2026-06-15 01:47:28 +00:00
feat: 乐云 directDownload 接口支持 & 缓存配置补充完善
- 新增 directDownload (GET) 接口,比 packageDownloadWithFileIds 少一次请求 - 每次随机选择下载方式,失败自动 fallback 到另一种 - 统一所有下载方法的 Promise 参数传递 - 添加 HTTP 状态码日志便于调试 - 优化 app-dev.yml 缓存配置注释,补充所有缺失的网盘类型
This commit is contained in:
@@ -15,6 +15,7 @@ import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
@@ -24,6 +25,7 @@ public class LeTool extends PanBase {
|
||||
private static final String API_URL_PREFIX = "https://lecloud.lenovo.com/mshare/api/clouddiskapi/share/public/v1/";
|
||||
private static final String DEFAULT_FILE_TYPE = "file";
|
||||
private static final int FILE_TYPE_DIRECTORY = 0; // 目录类型
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
private static final MultiMap HEADERS;
|
||||
|
||||
@@ -100,8 +102,8 @@ public class LeTool extends PanBase {
|
||||
}
|
||||
|
||||
String fileId = fileInfoJson.getString("fileId");
|
||||
// 根据文件ID获取跳转链接
|
||||
getDownURL(dataKey, fileId);
|
||||
// 根据文件ID获取跳转链接(随机选择方式,失败自动fallback)
|
||||
getDownURLWithFallback(dataKey, fileId);
|
||||
}
|
||||
} else {
|
||||
fail("{}: {}", resJson.getString("errcode"), resJson.getString("errmsg"));
|
||||
@@ -260,8 +262,8 @@ public class LeTool extends PanBase {
|
||||
String shareId = paramJson.getString("shareId");
|
||||
String fileId = paramJson.getString("fileId");
|
||||
|
||||
// 调用获取下载链接
|
||||
getDownURLForById(shareId, fileId, parsePromise);
|
||||
// 调用获取下载链接(随机选择方式,失败自动fallback)
|
||||
getDownURLWithFallbackForById(shareId, fileId, parsePromise);
|
||||
|
||||
} catch (Exception e) {
|
||||
parsePromise.fail("解析参数失败: " + e.getMessage());
|
||||
@@ -304,14 +306,22 @@ public class LeTool extends PanBase {
|
||||
}).onFailure(err -> promise.fail(err));
|
||||
}
|
||||
|
||||
private void getDownURL(String key, String fileId) {
|
||||
/**
|
||||
* 通过 packageDownloadWithFileIds 接口获取下载链接
|
||||
* 需要两步:先获取 downloadUrl,再请求 302 跳转
|
||||
*
|
||||
* @param shareId 分享ID
|
||||
* @param fileId 文件ID
|
||||
* @param promise 完成时会写入此 promise
|
||||
*/
|
||||
private void getDownURL(String shareId, String fileId, Promise<String> promise) {
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
JsonArray fileIds = JsonArray.of(fileId);
|
||||
String apiUrl2 = API_URL_PREFIX + "packageDownloadWithFileIds";
|
||||
String apiUrl = API_URL_PREFIX + "packageDownloadWithFileIds";
|
||||
// {"fileIds":[123],"shareId":"xxx","browserId":"uuid"}
|
||||
client.postAbs(apiUrl2)
|
||||
client.postAbs(apiUrl)
|
||||
.putHeaders(HEADERS)
|
||||
.sendJsonObject(JsonObject.of("fileIds", fileIds, "shareId", key, "browserId", uuid))
|
||||
.sendJsonObject(JsonObject.of("fileIds", fileIds, "shareId", shareId, "browserId", uuid))
|
||||
.onSuccess(res -> {
|
||||
JsonObject resJson = asJson(res);
|
||||
if (resJson.containsKey("result")) {
|
||||
@@ -320,20 +330,107 @@ public class LeTool extends PanBase {
|
||||
// 获取重定向链接跳转链接
|
||||
String downloadUrl = dataJson.getString("downloadUrl");
|
||||
if (downloadUrl == null) {
|
||||
fail("Result JSON数据异常: downloadUrl不存在");
|
||||
promise.fail("Result JSON数据异常: downloadUrl不存在");
|
||||
return;
|
||||
}
|
||||
// 获取重定向链接跳转链接
|
||||
clientNoRedirects.getAbs(downloadUrl).send()
|
||||
.onSuccess(res2 -> promise.complete(res2.headers().get("Location")))
|
||||
.onFailure(handleFail(downloadUrl));
|
||||
.onFailure(err -> promise.fail(err));
|
||||
} else {
|
||||
fail("{}: {}", resJson.getString("errcode"), resJson.getString("errmsg"));
|
||||
promise.fail(resJson.getString("errcode") + ": " + resJson.getString("errmsg"));
|
||||
}
|
||||
} else {
|
||||
fail("Result JSON数据异常: result字段不存在");
|
||||
promise.fail("Result JSON数据异常: result字段不存在");
|
||||
}
|
||||
}).onFailure(handleFail(apiUrl2));
|
||||
}).onFailure(err -> promise.fail(err));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 directDownload 接口获取下载链接
|
||||
* 相比 packageDownloadWithFileIds 少一次请求,直接返回302
|
||||
*
|
||||
* @param shareId 分享ID
|
||||
* @param fileId 文件ID
|
||||
* @param promise 完成时会写入此 promise
|
||||
*/
|
||||
private void getDownURLDirect(String shareId, String fileId, Promise<String> promise) {
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
String apiUrl = API_URL_PREFIX + "directDownload"
|
||||
+ "?shareId=" + shareId
|
||||
+ "&fileId=" + fileId
|
||||
+ "&browserId=" + uuid;
|
||||
|
||||
clientNoRedirects.getAbs(apiUrl)
|
||||
.putHeaders(HEADERS)
|
||||
.send()
|
||||
.onSuccess(res -> {
|
||||
String location = res.headers().get("Location");
|
||||
if (location != null && !location.isEmpty()) {
|
||||
promise.complete(location);
|
||||
} else {
|
||||
log.warn("directDownload 返回非302响应: shareId={}, fileId={}, statusCode={}", shareId, fileId, res.statusCode());
|
||||
promise.fail("directDownload 未返回有效的 Location, statusCode=" + res.statusCode());
|
||||
}
|
||||
})
|
||||
.onFailure(err -> {
|
||||
log.warn("directDownload 请求失败: shareId={}, fileId={}, error={}", shareId, fileId, err.getMessage());
|
||||
promise.fail(err);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机选择下载方式并带 fallback(用于 parse)
|
||||
* 先随机选择 directDownload 或 packageDownloadWithFileIds,失败则尝试另一个
|
||||
*/
|
||||
private void getDownURLWithFallback(String shareId, String fileId) {
|
||||
boolean useDirect = RANDOM.nextBoolean();
|
||||
log.info("乐云下载方式选择: shareId={}, fileId={}, method={}", shareId, fileId, useDirect ? "directDownload" : "packageDownloadWithFileIds");
|
||||
|
||||
Promise<String> fallbackPromise = Promise.promise();
|
||||
fallbackPromise.future().onSuccess(url -> {
|
||||
promise.complete(url);
|
||||
}).onFailure(err -> {
|
||||
log.warn("乐云第一种下载方式失败,尝试另一种: {}", err.getMessage());
|
||||
if (useDirect) {
|
||||
getDownURL(shareId, fileId, promise);
|
||||
} else {
|
||||
getDownURLDirect(shareId, fileId, promise);
|
||||
}
|
||||
});
|
||||
|
||||
if (useDirect) {
|
||||
getDownURLDirect(shareId, fileId, fallbackPromise);
|
||||
} else {
|
||||
getDownURL(shareId, fileId, fallbackPromise);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机选择下载方式并带 fallback(用于 parseById)
|
||||
* 先随机选择 directDownload 或 packageDownloadWithFileIds,失败则尝试另一个
|
||||
*/
|
||||
private void getDownURLWithFallbackForById(String shareId, String fileId, Promise<String> promise) {
|
||||
boolean useDirect = RANDOM.nextBoolean();
|
||||
log.info("乐云下载方式选择(parseById): shareId={}, fileId={}, method={}", shareId, fileId, useDirect ? "directDownload" : "packageDownloadWithFileIds");
|
||||
|
||||
Promise<String> fallbackPromise = Promise.promise();
|
||||
fallbackPromise.future().onSuccess(url -> {
|
||||
promise.complete(url);
|
||||
}).onFailure(err -> {
|
||||
log.warn("乐云第一种下载方式失败,尝试另一种: {}", err.getMessage());
|
||||
if (useDirect) {
|
||||
getDownURLForById(shareId, fileId, promise);
|
||||
} else {
|
||||
getDownURLDirect(shareId, fileId, promise);
|
||||
}
|
||||
});
|
||||
|
||||
if (useDirect) {
|
||||
getDownURLDirect(shareId, fileId, fallbackPromise);
|
||||
} else {
|
||||
getDownURLForById(shareId, fileId, fallbackPromise);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user