diff --git a/core/src/main/generated/cn/qaiu/vx/core/verticle/conf/HttpProxyConfConverter.java b/core/src/main/generated/cn/qaiu/vx/core/verticle/conf/HttpProxyConfConverter.java deleted file mode 100644 index 17b355a..0000000 --- a/core/src/main/generated/cn/qaiu/vx/core/verticle/conf/HttpProxyConfConverter.java +++ /dev/null @@ -1,73 +0,0 @@ -package cn.qaiu.vx.core.verticle.conf; - -import io.vertx.core.json.JsonObject; -import io.vertx.core.json.JsonArray; -import io.vertx.core.json.impl.JsonUtil; -import java.time.Instant; -import java.time.format.DateTimeFormatter; -import java.util.Base64; - -/** - * Converter and mapper for {@link cn.qaiu.vx.core.verticle.conf.HttpProxyConf}. - * NOTE: This class has been automatically generated from the {@link cn.qaiu.vx.core.verticle.conf.HttpProxyConf} original class using Vert.x codegen. - */ -public class HttpProxyConfConverter { - - - private static final Base64.Decoder BASE64_DECODER = JsonUtil.BASE64_DECODER; - private static final Base64.Encoder BASE64_ENCODER = JsonUtil.BASE64_ENCODER; - - static void fromJson(Iterable> json, HttpProxyConf obj) { - for (java.util.Map.Entry member : json) { - switch (member.getKey()) { - case "password": - if (member.getValue() instanceof String) { - obj.setPassword((String)member.getValue()); - } - break; - case "port": - if (member.getValue() instanceof Number) { - obj.setPort(((Number)member.getValue()).intValue()); - } - break; - case "preProxyOptions": - if (member.getValue() instanceof JsonObject) { - obj.setPreProxyOptions(new io.vertx.core.net.ProxyOptions((io.vertx.core.json.JsonObject)member.getValue())); - } - break; - case "timeout": - if (member.getValue() instanceof Number) { - obj.setTimeout(((Number)member.getValue()).intValue()); - } - break; - case "username": - if (member.getValue() instanceof String) { - obj.setUsername((String)member.getValue()); - } - break; - } - } - } - - static void toJson(HttpProxyConf obj, JsonObject json) { - toJson(obj, json.getMap()); - } - - static void toJson(HttpProxyConf obj, java.util.Map json) { - if (obj.getPassword() != null) { - json.put("password", obj.getPassword()); - } - if (obj.getPort() != null) { - json.put("port", obj.getPort()); - } - if (obj.getPreProxyOptions() != null) { - json.put("preProxyOptions", obj.getPreProxyOptions().toJson()); - } - if (obj.getTimeout() != null) { - json.put("timeout", obj.getTimeout()); - } - if (obj.getUsername() != null) { - json.put("username", obj.getUsername()); - } - } -} diff --git a/parser/pom.xml b/parser/pom.xml index 674a65d..a210e43 100644 --- a/parser/pom.xml +++ b/parser/pom.xml @@ -59,7 +59,7 @@ UTF-8 - 4.5.21 + 4.5.22 0.10.2 1.18.38 2.0.5 diff --git a/parser/src/main/java/cn/qaiu/parser/PanDomainTemplate.java b/parser/src/main/java/cn/qaiu/parser/PanDomainTemplate.java index 722e55c..85422bc 100644 --- a/parser/src/main/java/cn/qaiu/parser/PanDomainTemplate.java +++ b/parser/src/main/java/cn/qaiu/parser/PanDomainTemplate.java @@ -324,10 +324,10 @@ public enum PanDomainTemplate { // Cloudreve自定义域名解析, 解析器CeTool兜底策略, 即任意域名如果匹配不到对应的规则, 则由CeTool统一处理, // 如果不属于Cloudreve盘 则调用下一个自定义域名解析器, 若都处理不了则抛出异常, 这种匹配模式类似责任链 - // https://pan.huang1111.cn/s/xxx + // http(s)://pan.huang1111.cn/s/xxx // 通用域名([a-z\\d]+(-[a-z\\d]+)*\.)+[a-z]{2,} CE("Cloudreve", - compile("http(s)?://([a-zA-Z\\d]+(-[a-zA-Z\\d]+)*\\.)+[a-zA-Z]{2,}(/s)?/(?.+)"), + compile("http(s)?://([a-zA-Z\\d]+(-[a-zA-Z\\d]+)*\\.)+[a-zA-Z]{2,}(:\\d{1,5})?(/s)?/(?.+)"), "https://{any}/s/{shareKey}", "https://cloudreve.org/", CeTool.class), diff --git a/parser/src/main/java/cn/qaiu/parser/impl/Ce4Tool.java b/parser/src/main/java/cn/qaiu/parser/impl/Ce4Tool.java index baf5a5b..6cdb1c4 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/Ce4Tool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/Ce4Tool.java @@ -1,5 +1,6 @@ package cn.qaiu.parser.impl; +import cn.qaiu.entity.FileInfo; import cn.qaiu.entity.ShareLinkInfo; import cn.qaiu.parser.PanBase; import io.vertx.core.Future; @@ -9,6 +10,10 @@ import io.vertx.core.json.JsonObject; import io.vertx.ext.web.client.HttpRequest; import java.net.URL; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; /** * Cloudreve 4.x 自建网盘解析
@@ -18,13 +23,14 @@ import java.net.URL; public class Ce4Tool extends PanBase { // Cloudreve 4.x uses /api/v3/ prefix for most APIs - private static final String FILE_URL_API_PATH = "/api/v3/file/url"; - private static final String SHARE_API_PATH = "/api/v3/share/info/"; + private static final String FILE_URL_API_PATH = "/api/v4/file/url"; + private static final String SHARE_API_PATH = "/api/v4/share/info/"; public Ce4Tool(ShareLinkInfo shareLinkInfo) { super(shareLinkInfo); } + @Override public Future parse() { String key = shareLinkInfo.getShareKey(); String pwd = shareLinkInfo.getSharePassword(); @@ -32,6 +38,10 @@ public class Ce4Tool extends PanBase { try { URL url = new URL(shareLinkInfo.getShareUrl()); String baseUrl = url.getProtocol() + "://" + url.getHost(); + // 如果有端口,拼接上端口 + if (url.getPort() != -1) { + baseUrl += ":" + url.getPort(); + } // 获取分享信息 getShareInfo(baseUrl, key, pwd); @@ -45,6 +55,59 @@ public class Ce4Tool extends PanBase { * 获取Cloudreve 4.x分享信息 */ private void getShareInfo(String baseUrl, String key, String pwd) { + // 第一步:请求分享URL,获取302跳转地址 + String shareUrl = shareLinkInfo.getShareUrl(); + clientNoRedirects.getAbs(shareUrl).send().onSuccess(res -> { + try { + if (res.statusCode() == 302 || res.statusCode() == 301) { + String location = res.headers().get("Location"); + if (location == null || location.isEmpty()) { + fail("获取重定向地址失败: Location头为空"); + return; + } + + // 从Location URL中提取path参数 + String path = extractPathFromUrl(location); + if (path == null || path.isEmpty()) { + fail("从重定向URL中提取path参数失败: {}", location); + return; + } + + // 解码URI + String decodedPath = URLDecoder.decode(path, StandardCharsets.UTF_8); + + // 第二步:请求分享详情接口,获取文件名 + requestShareDetail(baseUrl, key, pwd, decodedPath); + } else { + fail("分享URL请求失败: 期望302/301重定向,实际状态码 {}", res.statusCode()); + } + } catch (Exception e) { + fail(e, "解析重定向响应失败"); + } + }).onFailure(handleFail(shareUrl)); + } + + /** + * 从URL中提取path参数 + */ + private String extractPathFromUrl(String url) { + try { + // 解析查询参数 + String[] keyValue = url.split("=", 2); + if (keyValue.length == 2 && keyValue[0].contains("path")) { + return keyValue[1]; + } + return null; + } catch (Exception e) { + log.error("解析URL失败: {}", url, e); + return null; + } + } + + /** + * 请求分享详情接口,获取文件名 + */ + private void requestShareDetail(String baseUrl, String key, String pwd, String path) { String shareApiUrl = baseUrl + SHARE_API_PATH + key; HttpRequest httpRequest = clientSession.getAbs(shareApiUrl); @@ -56,18 +119,24 @@ public class Ce4Tool extends PanBase { try { if (res.statusCode() == 200) { JsonObject jsonObject = asJson(res); + setFileInfo(jsonObject); if (jsonObject.containsKey("code")) { int code = jsonObject.getInteger("code"); if (code == 0) { // 成功,获取文件信息和下载链接 JsonObject data = jsonObject.getJsonObject("data"); if (data != null) { - // 获取文件路径,如果没有则使用默认路径 - String filePath = "/"; - if (data.containsKey("path")) { - filePath = data.getString("path"); + // 获取文件名 + String fileName = data.getString("name"); + if (fileName == null || fileName.isEmpty()) { + fail("分享信息中缺少name字段"); + return; } - // 对于4.x,需要通过 POST /api/v3/file/url 获取下载链接 + + // 拼接path和文件名 + String filePath = path + "/" + fileName; + + // 对于4.x,需要通过 POST /api/v4/file/url 获取下载链接 getDownloadUrl(baseUrl, filePath); } else { fail("分享信息获取失败: data字段为空"); @@ -91,6 +160,66 @@ public class Ce4Tool extends PanBase { }).onFailure(handleFail(shareApiUrl)); } + private void setFileInfo(JsonObject jsonObject) { + try { + JsonObject data = jsonObject.getJsonObject("data"); + if (data == null) { + return; + } + + FileInfo fileInfo = new FileInfo(); + + // 设置文件ID + if (data.containsKey("id")) { + fileInfo.setFileId(data.getString("id")); + } + + // 设置文件名 + if (data.containsKey("name")) { + fileInfo.setFileName(data.getString("name")); + } + + // 设置下载次数 + if (data.containsKey("downloaded")) { + fileInfo.setDownloadCount(data.getInteger("downloaded")); + } + + // 设置访问次数(visited) + // 注意:FileInfo 没有 visited 字段,可以放在 extParameters 中 + + // 设置创建者(从 owner 对象中获取) + if (data.containsKey("owner")) { + JsonObject owner = data.getJsonObject("owner"); + if (owner != null && owner.containsKey("nickname")) { + fileInfo.setCreateBy(owner.getString("nickname")); + } + } + + // 设置创建时间(格式化 ISO 8601 为 yyyy-MM-dd HH:mm:ss) + if (data.containsKey("created_at")) { + String createdAt = data.getString("created_at"); + if (createdAt != null && !createdAt.isEmpty()) { + try { + String formattedTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + .format(OffsetDateTime.parse(createdAt).toLocalDateTime()); + fileInfo.setCreateTime(formattedTime); + } catch (Exception e) { + log.warn("日期格式化失败: {}", createdAt, e); + // 如果格式化失败,直接使用原始值 + fileInfo.setCreateTime(createdAt); + } + } + } + + // 设置网盘类型 + fileInfo.setPanType(shareLinkInfo.getType()); + + shareLinkInfo.getOtherParam().put("fileInfo", fileInfo); + } catch (Exception e) { + log.warn("设置文件信息失败", e); + } + } + /** * 通过 POST /api/v3/file/url 获取下载链接 (Cloudreve 4.x API) */ @@ -109,9 +238,9 @@ public class Ce4Tool extends PanBase { try { if (res.statusCode() == 200) { JsonObject jsonObject = asJson(res); - if (jsonObject.containsKey("urls")) { - JsonArray urls = jsonObject.getJsonArray("urls"); - if (urls != null && urls.size() > 0) { + if (jsonObject.containsKey("data") && jsonObject.getJsonObject("data").containsKey("urls")) { + JsonArray urls = jsonObject.getJsonObject("data").getJsonArray("urls"); + if (urls != null && !urls.isEmpty()) { JsonObject urlObj = urls.getJsonObject(0); String downloadUrl = urlObj.getString("url"); if (downloadUrl != null && !downloadUrl.isEmpty()) { diff --git a/parser/src/main/java/cn/qaiu/parser/impl/CeTool.java b/parser/src/main/java/cn/qaiu/parser/impl/CeTool.java index 5a6f4b9..09f9956 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/CeTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/CeTool.java @@ -1,5 +1,6 @@ package cn.qaiu.parser.impl; +import cn.qaiu.entity.FileInfo; import cn.qaiu.entity.ShareLinkInfo; import cn.qaiu.parser.PanBase; import io.vertx.core.Future; @@ -8,6 +9,9 @@ import io.vertx.core.json.JsonObject; import io.vertx.ext.web.client.HttpRequest; import java.net.URL; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; /** * Cloudreve自建网盘解析
@@ -32,12 +36,17 @@ public class CeTool extends PanBase { } + @Override public Future parse() { String key = shareLinkInfo.getShareKey(); String pwd = shareLinkInfo.getSharePassword(); try { URL url = new URL(shareLinkInfo.getShareUrl()); String baseUrl = url.getProtocol() + "://" + url.getHost(); + // 如果有端口,拼接上端口 + if (url.getPort() != -1) { + baseUrl += ":" + url.getPort(); + } // 先检测API版本 detectVersionAndParse(baseUrl, key, pwd); @@ -49,96 +58,145 @@ public class CeTool extends PanBase { /** * 检测Cloudreve版本并选择合适的解析器 - * 先调用 /api/v3/site/ping 判断哪个API 如果/v3 或者/v4 能查询到json响应,可以判断是哪个版本 - * 不然返回404说明不是ce盘直接nextParser + * 检测策略: + * 1. 优先检测 v4 ping,如果成功且返回有效JSON,使用Ce4Tool + * 2. 如果 v4 ping 失败,检测 v3 ping + * 3. 如果 v3 ping 成功,尝试调用 v3 share API 来确认是否为 v3 + * 4. 如果 v3 share API 成功,使用 v3 逻辑 + * 5. 否则尝试下一个解析器 */ private void detectVersionAndParse(String baseUrl, String key, String pwd) { - String pingUrlV3 = baseUrl + PING_API_V3_PATH; - - // 先尝试v3 ping - clientSession.getAbs(pingUrlV3).send().onSuccess(res -> { - if (res.statusCode() == 200) { - try { - asJson(res); - // v3 ping成功,可能是3.x或4.x,尝试3.x的download API来判断 - String shareApiUrl = baseUrl + SHARE_API_PATH + key; - String downloadApiUrl = baseUrl + DOWNLOAD_API_PATH + key + "?path=undefined/undefined;"; - checkIfV3(shareApiUrl, downloadApiUrl, pwd); - } catch (Exception e) { - // JSON解析失败,尝试v4 ping - tryV4Ping(baseUrl, key, pwd); - } - } else if (res.statusCode() == 404) { - // v3 ping不存在,尝试v4 - tryV4Ping(baseUrl, key, pwd); - } else { - // 其他错误,不是Cloudreve盘 - nextParser(); - } - }).onFailure(t -> { - // 网络错误或不可达,尝试v4 ping - tryV4Ping(baseUrl, key, pwd); - }); + // 优先检测 v4 + tryV4Ping(baseUrl, key, pwd); } + /** + * 尝试 v4 ping,如果成功则使用 Ce4Tool + */ private void tryV4Ping(String baseUrl, String key, String pwd) { String pingUrlV4 = baseUrl + PING_API_V4_PATH; clientSession.getAbs(pingUrlV4).send().onSuccess(res -> { if (res.statusCode() == 200) { try { - asJson(res); - // v4 ping成功,使用Ce4Tool - delegateToCe4Tool(); + JsonObject json = asJson(res); + // v4 ping 成功且返回有效JSON,使用 Ce4Tool + if (json != null && !json.isEmpty()) { + log.debug("检测到Cloudreve 4.x (通过v4 ping)"); + delegateToCe4Tool(); + return; + } + } catch (Exception e) { + // JSON解析失败,继续尝试 v3 + log.debug("v4 ping返回非JSON响应,尝试v3"); + } + } + // v4 ping失败或返回非JSON,尝试 v3 + tryV3Ping(baseUrl, key, pwd); + }).onFailure(t -> { + // v4 ping 网络错误,尝试 v3 + log.debug("v4 ping请求失败,尝试v3: {}", t.getMessage()); + tryV3Ping(baseUrl, key, pwd); + }); + } + + /** + * 尝试 v3 ping,如果成功则验证是否为真正的 v3 + */ + private void tryV3Ping(String baseUrl, String key, String pwd) { + String pingUrlV3 = baseUrl + PING_API_V3_PATH; + + clientSession.getAbs(pingUrlV3).send().onSuccess(res -> { + if (res.statusCode() == 200) { + try { + JsonObject json = asJson(res); + // v3 ping 成功且返回有效JSON,进一步验证是否为 v3 + if (json != null && !json.isEmpty()) { + // 尝试调用 v3 share API 来确认 + verifyV3AndParse(baseUrl, key, pwd); + return; + } } catch (Exception e) { // JSON解析失败,不是Cloudreve盘 - nextParser(); + log.debug("v3 ping返回非JSON响应,不是Cloudreve盘"); } - } else { - // v4 ping失败,不是Cloudreve盘 - nextParser(); } + // v3 ping失败,不是Cloudreve盘 + log.debug("v3 ping失败,尝试下一个解析器"); + nextParser(); }).onFailure(t -> { - // 网络错误,尝试下一个解析器 + // v3 ping 网络错误,不是Cloudreve盘 + log.debug("v3 ping请求失败,尝试下一个解析器: {}", t.getMessage()); nextParser(); }); } /** - * 检查是否是3.x版本,通过尝试调用3.x的API + * 验证是否为 v3 版本并解析 + * 通过调用 v3 share API 来确认,如果成功则使用 v3 逻辑 */ - private void checkIfV3(String shareApiUrl, String downloadApiUrl, String pwd) { + private void verifyV3AndParse(String baseUrl, String key, String pwd) { + String shareApiUrl = baseUrl + SHARE_API_PATH + key; HttpRequest httpRequest = clientSession.getAbs(shareApiUrl); - if (pwd != null) { + if (pwd != null && !pwd.isEmpty()) { httpRequest.addQueryParam("password", pwd); } httpRequest.send().onSuccess(res -> { try { - if (res.statusCode() == 200 && res.bodyAsJsonObject().containsKey("code")) { - // share API成功,尝试download API - clientSession.putAbs(downloadApiUrl).send().onSuccess(res2 -> { - if (res2.statusCode() == 200 || res2.statusCode() == 400) { - // 3.x版本的download API存在 - getDownURL(downloadApiUrl); - } else if (res2.statusCode() == 404 || res2.statusCode() == 405) { - // download API不存在,说明是4.x - delegateToCe4Tool(); - } else { - // 其他错误,可能是4.x - delegateToCe4Tool(); - } - }).onFailure(t -> { - // 请求失败,尝试4.x - delegateToCe4Tool(); - }); - } else { - nextParser(); + if (res.statusCode() == 200) { + JsonObject jsonObject = asJson(res); + // 检查响应格式是否符合 v3 API + if (jsonObject.containsKey("code") && jsonObject.getInteger("code") == 0) { + // v3 share API 成功,确认是 v3 版本 + // 设置文件信息 + setFileInfo(jsonObject); + log.debug("确认是Cloudreve 3.x,使用v3下载API"); + String downloadApiUrl = baseUrl + DOWNLOAD_API_PATH + key + "?path=undefined/undefined;"; + getDownURL(downloadApiUrl); + return; + } } } catch (Exception e) { - nextParser(); + log.debug("v3 share API解析失败: {}", e.getMessage()); } }).onFailure(t -> { + log.debug("v3 share API请求失败: {}", t.getMessage()); + // 请求失败,尝试 v4 或下一个解析器 + tryV4ShareApi(baseUrl, key, pwd); + }); + } + + /** + * 尝试 v4 share API,如果成功则使用 Ce4Tool + */ + private void tryV4ShareApi(String baseUrl, String key, String pwd) { + String shareApiUrl = baseUrl + "/api/v4/share/info/" + key; + HttpRequest httpRequest = clientSession.getAbs(shareApiUrl); + if (pwd != null && !pwd.isEmpty()) { + httpRequest.addQueryParam("password", pwd); + } + + httpRequest.send().onSuccess(res -> { + try { + if (res.statusCode() == 200) { + JsonObject jsonObject = asJson(res); + // 检查响应格式是否符合 v4 API + if (jsonObject.containsKey("code") && jsonObject.getInteger("code") == 0) { + // v4 share API 成功,使用 Ce4Tool + log.debug("确认是Cloudreve 4.x (通过v4 share API)"); + delegateToCe4Tool(); + return; + } + } + } catch (Exception e) { + log.debug("v4 share API解析失败: {}", e.getMessage()); + } + // v4 share API 也失败,不是Cloudreve盘 + log.debug("v4 share API验证失败,尝试下一个解析器"); + nextParser(); + }).onFailure(t -> { + log.debug("v4 share API请求失败,尝试下一个解析器: {}", t.getMessage()); nextParser(); }); } @@ -152,10 +210,87 @@ public class CeTool extends PanBase { } + /** + * 设置文件信息(Cloudreve 3.x) + */ + private void setFileInfo(JsonObject jsonObject) { + try { + JsonObject data = jsonObject.getJsonObject("data"); + if (data == null) { + return; + } + + FileInfo fileInfo = new FileInfo(); + + // 设置文件ID + if (data.containsKey("key")) { + fileInfo.setFileId(data.getString("key")); + } + + // 设置文件名(从 source 对象中获取) + if (data.containsKey("source")) { + JsonObject source = data.getJsonObject("source"); + if (source != null) { + if (source.containsKey("name")) { + fileInfo.setFileName(source.getString("name")); + } + if (source.containsKey("size")) { + fileInfo.setSize(source.getLong("size")); + } + } + } + + // 设置下载次数 + if (data.containsKey("downloads")) { + fileInfo.setDownloadCount(data.getInteger("downloads")); + } + + // 设置创建者(从 creator 对象中获取) + if (data.containsKey("creator")) { + JsonObject creator = data.getJsonObject("creator"); + if (creator != null && creator.containsKey("nick")) { + fileInfo.setCreateBy(creator.getString("nick")); + } + } + + // 设置创建时间(格式化 ISO 8601 为 yyyy-MM-dd HH:mm:ss) + if (data.containsKey("create_date")) { + String createDate = data.getString("create_date"); + if (createDate != null && !createDate.isEmpty()) { + try { + String formattedTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + .format(OffsetDateTime.parse(createDate).toLocalDateTime()); + fileInfo.setCreateTime(formattedTime); + } catch (Exception e) { + log.warn("日期格式化失败: {}", createDate, e); + // 如果格式化失败,直接使用原始值 + fileInfo.setCreateTime(createDate); + } + } + } + + // 设置访问次数(views)到扩展参数中 + if (data.containsKey("views")) { + if (fileInfo.getExtParameters() == null) { + fileInfo.setExtParameters(new HashMap<>()); + } + fileInfo.getExtParameters().put("views", data.getInteger("views")); + } + + // 设置网盘类型 + fileInfo.setPanType(shareLinkInfo.getType()); + + shareLinkInfo.getOtherParam().put("fileInfo", fileInfo); + } catch (Exception e) { + log.warn("设置文件信息失败", e); + } + } + private void getDownURL(String shareApiUrl) { - clientSession.putAbs(shareApiUrl).send().onSuccess(res -> { + clientSession.putAbs(shareApiUrl) + .putHeader("Referer", shareLinkInfo.getShareUrl()) + .send().onSuccess(res -> { JsonObject jsonObject = asJson(res); - System.out.println(jsonObject.encodePrettily()); if (jsonObject.containsKey("code") && jsonObject.getInteger("code") == 0) { promise.complete(jsonObject.getString("data")); } else { diff --git a/pom.xml b/pom.xml index d06b29d..5292309 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ ${project.basedir}/web-service/target/package - 4.5.21 + 4.5.22 0.10.2 1.18.38 2.0.5 diff --git a/web-front/src/views/Home.vue b/web-front/src/views/Home.vue index c4e21ce..3dcac8a 100644 --- a/web-front/src/views/Home.vue +++ b/web-front/src/views/Home.vue @@ -91,7 +91,7 @@ 生成Markdown 扫码下载 分享统计 - 客户端链接(实验) + 客户端链接(实验)

diff --git a/web-service/doc/README.md b/web-service/doc/README.md new file mode 100644 index 0000000..095939c --- /dev/null +++ b/web-service/doc/README.md @@ -0,0 +1,89 @@ +# API 文档说明 + +本目录包含网盘快速下载服务的完整 API 文档。 + +## 文件说明 + +### 1. API_DOCUMENTATION.md +详细的接口说明文档,包含: +- 所有接口的详细说明 +- 请求参数和响应格式 +- 使用示例 +- 错误处理说明 +- 注意事项 + +### 2. openapi.json +OpenAPI 3.0 规范的 JSON 文件,可用于: +- 导入到 API 测试工具(如 Apifox、Postman、Swagger UI 等) +- 生成客户端 SDK +- API 文档自动生成 + +### 3. CLIENT_LINKS_API.md +客户端下载链接 API 的详细说明文档(已存在) + +## 如何使用 + +### 导入到 Apifox + +1. 打开 Apifox +2. 选择项目 → 导入 +3. 选择 "OpenAPI" 格式 +4. 选择 `openapi.json` 文件 +5. 点击导入 + +### 导入到 Postman + +1. 打开 Postman +2. 点击 Import +3. 选择 "File" 标签 +4. 选择 `openapi.json` 文件 +5. 点击 Import + +### 使用 Swagger UI 查看 + +1. 访问 [Swagger Editor](https://editor.swagger.io/) +2. 将 `openapi.json` 的内容复制粘贴到编辑器中 +3. 即可查看和测试所有接口 + +## 接口分类 + +### 解析相关接口 +- `/parser` - 解析分享链接(重定向) +- `/json/parser` - 解析分享链接(JSON) +- `/:type/:key` - 根据类型和Key解析(重定向) +- `/json/:type/:key` - 根据类型和Key解析(JSON) +- `/v2/linkInfo` - 获取链接信息 + +### 文件列表接口 +- `/v2/getFileList` - 获取文件列表 + +### 预览接口 +- `/v2/view/:type/:key` - 预览媒体文件(按类型和Key) +- `/v2/preview` - 预览媒体文件(按URL) +- `/v2/viewUrl/:type/:param` - 预览URL(目录预览) + +### 客户端下载链接接口 +- `/v2/clientLinks` - 获取所有客户端下载链接 +- `/v2/clientLink` - 获取指定类型的客户端下载链接 + +### 统计信息接口 +- `/v2/statisticsInfo` - 获取统计信息 + +### 网盘列表接口 +- `/v2/getPanList` - 获取支持的网盘列表 + +### 版本信息接口 +- `/v2/build-version` - 获取版本号 + +### 隔空喊话接口 +- `/v2/shout/submit` - 提交消息 +- `/v2/shout/retrieve` - 检索消息 + +### 快捷下载接口 +- `/d/:type/:key` - 下载重定向(短链) +- `/v2/redirectUrl/:type/:param` - 重定向下载URL(目录文件) + +## 更新日志 + +- 2025-01-21: 初始版本,包含所有接口的完整文档 + diff --git a/web-service/doc/openapi.json b/web-service/doc/openapi.json new file mode 100644 index 0000000..f29d7c4 --- /dev/null +++ b/web-service/doc/openapi.json @@ -0,0 +1,1381 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "网盘快速下载服务 API", + "description": "网盘快速下载服务 REST API 文档,支持多种网盘的分享链接解析,提供直链下载、预览、客户端下载链接等功能", + "version": "1.0.0", + "contact": { + "name": "API Support", + "url": "https://qaiu.top" + } + }, + "servers": [ + { + "url": "http://localhost:6400", + "description": "本地开发环境" + }, + { + "url": "https://lzzz.qaiu.top", + "description": "生产环境" + } + ], + "tags": [ + { + "name": "解析接口", + "description": "分享链接解析相关接口" + }, + { + "name": "文件列表", + "description": "文件列表相关接口" + }, + { + "name": "预览接口", + "description": "媒体文件预览相关接口" + }, + { + "name": "客户端下载", + "description": "客户端下载链接相关接口" + }, + { + "name": "统计信息", + "description": "统计信息相关接口" + }, + { + "name": "网盘列表", + "description": "支持的网盘列表接口" + }, + { + "name": "版本信息", + "description": "版本信息接口" + }, + { + "name": "隔空喊话", + "description": "隔空喊话相关接口" + }, + { + "name": "快捷下载", + "description": "快捷下载重定向接口" + } + ], + "paths": { + "/parser": { + "get": { + "tags": ["解析接口"], + "summary": "解析分享链接(重定向)", + "description": "解析分享链接并重定向到直链下载地址", + "parameters": [ + { + "name": "url", + "in": "query", + "required": true, + "description": "分享链接", + "schema": { + "type": "string", + "example": "https://pan.baidu.com/s/1test123" + } + }, + { + "name": "pwd", + "in": "query", + "required": false, + "description": "提取码", + "schema": { + "type": "string", + "example": "1234" + } + } + ], + "responses": { + "302": { + "description": "重定向到直链下载地址", + "headers": { + "nfd-cache-hit": { + "description": "是否命中缓存", + "schema": { + "type": "string", + "example": "true" + } + }, + "nfd-cache-expires": { + "description": "缓存过期时间", + "schema": { + "type": "string", + "example": "2025-01-22 12:00:00" + } + }, + "Location": { + "description": "重定向地址", + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "解析失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/json/parser": { + "get": { + "tags": ["解析接口"], + "summary": "解析分享链接(JSON)", + "description": "解析分享链接并返回JSON格式的直链信息", + "parameters": [ + { + "name": "url", + "in": "query", + "required": true, + "description": "分享链接", + "schema": { + "type": "string", + "example": "https://pan.baidu.com/s/1test123" + } + }, + { + "name": "pwd", + "in": "query", + "required": false, + "description": "提取码", + "schema": { + "type": "string", + "example": "1234" + } + } + ], + "responses": { + "200": { + "description": "解析成功", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CacheLinkInfo" + } + } + } + }, + "500": { + "description": "解析失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/{type}/{key}": { + "get": { + "tags": ["解析接口"], + "summary": "根据类型和Key解析(重定向)", + "description": "根据网盘类型和分享Key解析并重定向到直链", + "parameters": [ + { + "name": "type", + "in": "path", + "required": true, + "description": "网盘类型标识(如: lz, pan, cow等)", + "schema": { + "type": "string", + "example": "lz" + } + }, + { + "name": "key", + "in": "path", + "required": true, + "description": "分享Key,如果包含提取码,格式为 key@pwd", + "schema": { + "type": "string", + "example": "ia2cntg" + } + } + ], + "responses": { + "302": { + "description": "重定向到直链下载地址", + "headers": { + "nfd-cache-hit": { + "description": "是否命中缓存", + "schema": { + "type": "string" + } + }, + "nfd-cache-expires": { + "description": "缓存过期时间", + "schema": { + "type": "string" + } + }, + "Location": { + "description": "重定向地址", + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "解析失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/json/{type}/{key}": { + "get": { + "tags": ["解析接口"], + "summary": "根据类型和Key解析(JSON)", + "description": "根据网盘类型和分享Key解析并返回JSON格式的直链信息", + "parameters": [ + { + "name": "type", + "in": "path", + "required": true, + "description": "网盘类型标识", + "schema": { + "type": "string", + "example": "lz" + } + }, + { + "name": "key", + "in": "path", + "required": true, + "description": "分享Key,如果包含提取码,格式为 key@pwd", + "schema": { + "type": "string", + "example": "ia2cntg" + } + } + ], + "responses": { + "200": { + "description": "解析成功", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CacheLinkInfo" + } + } + } + }, + "500": { + "description": "解析失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/v2/linkInfo": { + "get": { + "tags": ["解析接口"], + "summary": "获取链接信息", + "description": "获取分享链接的详细信息,包括下载链接、预览链接、统计信息等", + "parameters": [ + { + "name": "url", + "in": "query", + "required": true, + "description": "分享链接", + "schema": { + "type": "string", + "example": "https://pan.baidu.com/s/1test123" + } + }, + { + "name": "pwd", + "in": "query", + "required": false, + "description": "提取码", + "schema": { + "type": "string", + "example": "1234" + } + } + ], + "responses": { + "200": { + "description": "获取成功", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LinkInfoResp" + } + } + } + }, + "500": { + "description": "获取失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/v2/getFileList": { + "get": { + "tags": ["文件列表"], + "summary": "获取文件列表", + "description": "获取分享链接中的文件列表(适用于目录分享)", + "parameters": [ + { + "name": "url", + "in": "query", + "required": true, + "description": "分享链接", + "schema": { + "type": "string", + "example": "https://pan.baidu.com/s/1test123" + } + }, + { + "name": "pwd", + "in": "query", + "required": false, + "description": "提取码", + "schema": { + "type": "string", + "example": "1234" + } + }, + { + "name": "dirId", + "in": "query", + "required": false, + "description": "目录ID,用于获取指定目录下的文件", + "schema": { + "type": "string", + "example": "dir123" + } + }, + { + "name": "uuid", + "in": "query", + "required": false, + "description": "UUID,某些网盘需要此参数", + "schema": { + "type": "string", + "example": "uuid123" + } + } + ], + "responses": { + "200": { + "description": "获取成功", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileInfo" + } + } + } + } + }, + "500": { + "description": "获取失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/v2/view/{type}/{key}": { + "get": { + "tags": ["预览接口"], + "summary": "预览媒体文件(按类型和Key)", + "description": "预览指定类型和Key的媒体文件(图片、视频等)", + "parameters": [ + { + "name": "type", + "in": "path", + "required": true, + "description": "网盘类型标识", + "schema": { + "type": "string", + "example": "pan" + } + }, + { + "name": "key", + "in": "path", + "required": true, + "description": "分享Key,如果包含提取码,格式为 key@pwd", + "schema": { + "type": "string", + "example": "1test123" + } + } + ], + "responses": { + "302": { + "description": "重定向到预览页面", + "headers": { + "Location": { + "description": "预览页面地址", + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "预览失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/v2/preview": { + "get": { + "tags": ["预览接口"], + "summary": "预览媒体文件(按URL)", + "description": "通过分享链接预览媒体文件", + "parameters": [ + { + "name": "url", + "in": "query", + "required": true, + "description": "分享链接", + "schema": { + "type": "string", + "example": "https://pan.baidu.com/s/1test123" + } + }, + { + "name": "pwd", + "in": "query", + "required": false, + "description": "提取码", + "schema": { + "type": "string", + "example": "1234" + } + } + ], + "responses": { + "302": { + "description": "重定向到预览页面", + "headers": { + "Location": { + "description": "预览页面地址", + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "预览失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/v2/viewUrl/{type}/{param}": { + "get": { + "tags": ["预览接口"], + "summary": "预览URL(目录预览)", + "description": "预览目录中的文件,param为Base64编码的参数", + "parameters": [ + { + "name": "type", + "in": "path", + "required": true, + "description": "网盘类型标识", + "schema": { + "type": "string", + "example": "pan" + } + }, + { + "name": "param", + "in": "path", + "required": true, + "description": "Base64编码的参数JSON", + "schema": { + "type": "string", + "example": "eyJmaWxlSWQiOiIxMjM0NTYifQ==" + } + } + ], + "responses": { + "302": { + "description": "重定向到预览页面", + "headers": { + "Location": { + "description": "预览页面地址", + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "预览失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/v2/clientLinks": { + "get": { + "tags": ["客户端下载"], + "summary": "获取所有客户端下载链接", + "description": "获取所有支持的客户端格式的下载链接", + "parameters": [ + { + "name": "url", + "in": "query", + "required": true, + "description": "分享链接", + "schema": { + "type": "string", + "example": "https://pan.baidu.com/s/1test123" + } + }, + { + "name": "pwd", + "in": "query", + "required": false, + "description": "提取码", + "schema": { + "type": "string", + "example": "1234" + } + } + ], + "responses": { + "200": { + "description": "获取成功", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientLinkResp" + } + } + } + }, + "500": { + "description": "获取失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/v2/clientLink": { + "get": { + "tags": ["客户端下载"], + "summary": "获取指定类型的客户端下载链接", + "description": "获取指定客户端类型的下载链接", + "parameters": [ + { + "name": "url", + "in": "query", + "required": true, + "description": "分享链接", + "schema": { + "type": "string", + "example": "https://pan.baidu.com/s/1test123" + } + }, + { + "name": "pwd", + "in": "query", + "required": false, + "description": "提取码", + "schema": { + "type": "string", + "example": "1234" + } + }, + { + "name": "clientType", + "in": "query", + "required": true, + "description": "客户端类型 (curl, wget, aria2, idm, thunder, bitcomet, motrix, fdm, powershell)", + "schema": { + "type": "string", + "enum": ["curl", "wget", "aria2", "idm", "thunder", "bitcomet", "motrix", "fdm", "powershell"], + "example": "curl" + } + } + ], + "responses": { + "200": { + "description": "获取成功", + "content": { + "text/plain": { + "schema": { + "type": "string", + "example": "curl -L -H \"User-Agent: Mozilla/5.0...\" -o \"test-file.zip\" \"https://example.com/file.zip\"" + } + } + } + }, + "500": { + "description": "获取失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/v2/statisticsInfo": { + "get": { + "tags": ["统计信息"], + "summary": "获取统计信息", + "description": "获取系统统计信息,包括解析总数、缓存总数等", + "responses": { + "200": { + "description": "获取成功", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatisticsInfo" + } + } + } + }, + "500": { + "description": "获取失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/v2/getPanList": { + "get": { + "tags": ["网盘列表"], + "summary": "获取支持的网盘列表", + "description": "获取所有支持的网盘列表及其信息", + "responses": { + "200": { + "description": "获取成功", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PanInfo" + } + } + } + } + } + } + } + }, + "/v2/build-version": { + "get": { + "tags": ["版本信息"], + "summary": "获取版本号", + "description": "获取应用版本号", + "responses": { + "200": { + "description": "获取成功", + "content": { + "text/plain": { + "schema": { + "type": "string", + "example": "20250121_101530" + } + } + } + } + } + } + }, + "/v2/shout/submit": { + "post": { + "tags": ["隔空喊话"], + "summary": "提交消息", + "description": "提交一条隔空喊话消息,返回6位提取码", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["content"], + "properties": { + "content": { + "type": "string", + "description": "消息内容", + "example": "Hello World!" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "提交成功", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JsonResult" + }, + "example": { + "code": 200, + "msg": "success", + "success": true, + "data": "123456", + "timestamp": 1705896000000 + } + } + } + }, + "500": { + "description": "提交失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/v2/shout/retrieve": { + "get": { + "tags": ["隔空喊话"], + "summary": "检索消息", + "description": "根据提取码检索消息", + "parameters": [ + { + "name": "code", + "in": "query", + "required": true, + "description": "6位提取码", + "schema": { + "type": "string", + "pattern": "^[0-9]{6}$", + "example": "123456" + } + } + ], + "responses": { + "200": { + "description": "检索成功", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ShoutMessage" + } + } + } + }, + "500": { + "description": "检索失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/d/{type}/{key}": { + "get": { + "tags": ["快捷下载"], + "summary": "下载重定向(短链)", + "description": "短链形式的下载重定向,等同于 /:type/:key", + "parameters": [ + { + "name": "type", + "in": "path", + "required": true, + "description": "网盘类型标识", + "schema": { + "type": "string", + "example": "lz" + } + }, + { + "name": "key", + "in": "path", + "required": true, + "description": "分享Key,如果包含提取码,格式为 key@pwd", + "schema": { + "type": "string", + "example": "ia2cntg" + } + } + ], + "responses": { + "302": { + "description": "重定向到直链下载地址", + "headers": { + "Location": { + "description": "重定向地址", + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "解析失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/v2/redirectUrl/{type}/{param}": { + "get": { + "tags": ["快捷下载"], + "summary": "重定向下载URL(目录文件)", + "description": "重定向到目录中指定文件的下载地址,param为Base64编码的参数", + "parameters": [ + { + "name": "type", + "in": "path", + "required": true, + "description": "网盘类型标识", + "schema": { + "type": "string", + "example": "pan" + } + }, + { + "name": "param", + "in": "path", + "required": true, + "description": "Base64编码的参数JSON", + "schema": { + "type": "string", + "example": "eyJmaWxlSWQiOiIxMjM0NTYifQ==" + } + } + ], + "responses": { + "302": { + "description": "重定向到直链下载地址", + "headers": { + "Location": { + "description": "重定向地址", + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "解析失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "CacheLinkInfo": { + "type": "object", + "properties": { + "shareKey": { + "type": "string", + "description": "缓存key: type:ShareKey", + "example": "lz:ia2cntg" + }, + "directLink": { + "type": "string", + "description": "解析后的直链", + "example": "https://example.com/download/file.zip" + }, + "cacheHit": { + "type": "boolean", + "description": "是否命中缓存", + "example": false + }, + "expires": { + "type": "string", + "description": "到期时间 yyyy-MM-dd hh:mm:ss", + "example": "2025-01-22 12:00:00" + }, + "expiration": { + "type": "integer", + "format": "int64", + "description": "有效期(毫秒)", + "example": 86400000 + }, + "fileInfo": { + "$ref": "#/components/schemas/FileInfo" + } + } + }, + "FileInfo": { + "type": "object", + "properties": { + "fileName": { + "type": "string", + "description": "文件名", + "example": "file.zip" + }, + "fileId": { + "type": "string", + "description": "文件ID", + "example": "123456" + }, + "fileIcon": { + "type": "string", + "description": "文件图标", + "example": "icon.png" + }, + "size": { + "type": "integer", + "format": "int64", + "description": "文件大小(byte)", + "example": 1024000 + }, + "sizeStr": { + "type": "string", + "description": "文件大小字符串", + "example": "1MB" + }, + "fileType": { + "type": "string", + "description": "文件类型", + "example": "zip" + }, + "filePath": { + "type": "string", + "description": "文件路径", + "example": "/folder/file.zip" + }, + "createTime": { + "type": "string", + "description": "创建(上传)时间 yyyy-MM-dd HH:mm:ss格式", + "example": "2025-01-21 10:00:00" + }, + "updateTime": { + "type": "string", + "description": "上次修改时间", + "example": "2025-01-21 11:00:00" + }, + "createBy": { + "type": "string", + "description": "创建者", + "example": "user123" + }, + "description": { + "type": "string", + "description": "文件描述" + }, + "downloadCount": { + "type": "integer", + "description": "下载次数", + "example": 10 + }, + "panType": { + "type": "string", + "description": "网盘标识", + "example": "lz" + }, + "parserUrl": { + "type": "string", + "description": "nfd下载链接(可能获取不到)" + }, + "previewUrl": { + "type": "string", + "description": "预览地址" + }, + "hash": { + "type": "string", + "description": "文件hash默认类型为md5" + }, + "extParameters": { + "type": "object", + "description": "扩展参数", + "additionalProperties": true + } + } + }, + "LinkInfoResp": { + "type": "object", + "properties": { + "downLink": { + "type": "string", + "description": "下载链接", + "example": "http://127.0.0.1:6400/d/pan/1test123" + }, + "apiLink": { + "type": "string", + "description": "API链接", + "example": "http://127.0.0.1:6400/json/pan/1test123" + }, + "viewLink": { + "type": "string", + "description": "预览链接", + "example": "http://127.0.0.1:6400/v2/view/pan/1test123" + }, + "cacheHitTotal": { + "type": "integer", + "description": "缓存命中总数", + "example": 10 + }, + "parserTotal": { + "type": "integer", + "description": "解析总数", + "example": 5 + }, + "sumTotal": { + "type": "integer", + "description": "总次数", + "example": 15 + }, + "shareLinkInfo": { + "$ref": "#/components/schemas/ShareLinkInfo" + } + } + }, + "ShareLinkInfo": { + "type": "object", + "properties": { + "shareKey": { + "type": "string", + "description": "分享键", + "example": "1test123" + }, + "panName": { + "type": "string", + "description": "网盘名称", + "example": "百度网盘" + }, + "type": { + "type": "string", + "description": "分享类型", + "example": "pan" + }, + "sharePassword": { + "type": "string", + "description": "分享密码(如果存在)", + "example": "1234" + }, + "shareUrl": { + "type": "string", + "description": "原始分享链接", + "example": "https://pan.baidu.com/s/1test123" + }, + "standardUrl": { + "type": "string", + "description": "规范化的标准链接", + "example": "https://pan.baidu.com/s/1test123" + }, + "otherParam": { + "type": "object", + "description": "其他参数", + "additionalProperties": true + } + } + }, + "ClientLinkResp": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "是否成功", + "example": true + }, + "error": { + "type": "string", + "description": "错误信息" + }, + "directLink": { + "type": "string", + "description": "直链URL", + "example": "https://example.com/file.zip" + }, + "fileName": { + "type": "string", + "description": "文件名", + "example": "test-file.zip" + }, + "fileSize": { + "type": "integer", + "format": "int64", + "description": "文件大小", + "example": 1024000 + }, + "clientLinks": { + "type": "object", + "description": "所有客户端下载链接", + "additionalProperties": { + "type": "string" + }, + "example": { + "CURL": "curl -L -H \"User-Agent: Mozilla/5.0...\" -o \"test-file.zip\" \"https://example.com/file.zip\"", + "POWERSHELL": "$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession...", + "ARIA2": "aria2c --header=\"User-Agent: Mozilla/5.0...\" --out=\"test-file.zip\" \"https://example.com/file.zip\"" + } + }, + "supportedClients": { + "type": "object", + "description": "支持的客户端类型列表", + "additionalProperties": { + "type": "string" + }, + "example": { + "curl": "cURL 命令", + "wget": "wget 命令", + "aria2": "Aria2" + } + }, + "parserInfo": { + "type": "string", + "description": "解析信息", + "example": "百度网盘 - pan" + } + } + }, + "StatisticsInfo": { + "type": "object", + "properties": { + "parserTotal": { + "type": "integer", + "description": "解析总数", + "example": 1000 + }, + "cacheTotal": { + "type": "integer", + "description": "缓存总数", + "example": 500 + }, + "total": { + "type": "integer", + "description": "总次数", + "example": 1500 + } + } + }, + "PanInfo": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "网盘名", + "example": "蓝奏云" + }, + "type": { + "type": "string", + "description": "网盘标识", + "example": "lz" + }, + "shareUrlFormat": { + "type": "string", + "description": "分享链接格式", + "example": "https://www.lanzou*.com/s/{shareKey}" + }, + "url": { + "type": "string", + "description": "网盘域名地址", + "example": "https://www.lanzou.com" + } + } + }, + "ShoutMessage": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "description": "消息ID" + }, + "code": { + "type": "string", + "description": "6位提取码", + "example": "123456", + "pattern": "^[0-9]{6}$" + }, + "content": { + "type": "string", + "description": "消息内容", + "example": "Hello World!" + }, + "ip": { + "type": "string", + "description": "发送者IP", + "example": "127.0.0.1" + }, + "createTime": { + "type": "string", + "format": "date-time", + "description": "创建时间", + "example": "2025-01-21T10:00:00" + }, + "expireTime": { + "type": "string", + "format": "date-time", + "description": "过期时间", + "example": "2025-01-22T10:00:00" + }, + "isUsed": { + "type": "boolean", + "description": "是否已使用", + "example": false + } + } + }, + "JsonResult": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "状态码", + "example": 200 + }, + "msg": { + "type": "string", + "description": "消息", + "example": "success" + }, + "success": { + "type": "boolean", + "description": "是否成功", + "example": true + }, + "data": { + "description": "数据", + "oneOf": [ + { + "type": "string" + }, + { + "type": "object" + }, + { + "type": "array" + } + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "时间戳", + "example": 1705896000000 + } + } + }, + "ErrorResponse": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "错误状态码", + "example": 500 + }, + "msg": { + "type": "string", + "description": "错误消息", + "example": "解析分享链接失败: 具体错误信息" + }, + "success": { + "type": "boolean", + "description": "是否成功", + "example": false + }, + "data": { + "type": "object", + "nullable": true + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "时间戳", + "example": 1705896000000 + } + } + } + } + } +} +