From e07ce15228ce28cdc515fe60b0ed713bba979bfd Mon Sep 17 00:00:00 2001 From: QAIU <736226400@qq.com> Date: Mon, 10 Feb 2025 14:19:18 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=96=87=E4=BB=B6=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E8=A7=A3=E6=9E=90=E6=8E=A5=E5=8F=A3/redirectUrl/:type?= =?UTF-8?q?/:param?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/qaiu/entity/FileInfo.java | 49 ++++++++++--- .../main/java/cn/qaiu/parser/IPanTool.java | 2 +- .../src/main/java/cn/qaiu/parser/PanBase.java | 4 ++ .../main/java/cn/qaiu/parser/impl/FjTool.java | 70 +++++++++++++++++-- .../main/java/cn/qaiu/parser/impl/IzTool.java | 61 +++++++++++++--- .../main/java/cn/qaiu/parser/impl/LzTool.java | 18 ++--- .../cn/qaiu/lz/web/controller/ParserApi.java | 43 ++++++++++-- 7 files changed, 209 insertions(+), 38 deletions(-) diff --git a/parser/src/main/java/cn/qaiu/entity/FileInfo.java b/parser/src/main/java/cn/qaiu/entity/FileInfo.java index b226020..9ffacce 100644 --- a/parser/src/main/java/cn/qaiu/entity/FileInfo.java +++ b/parser/src/main/java/cn/qaiu/entity/FileInfo.java @@ -58,10 +58,21 @@ public class FileInfo { */ private Integer downloadCount; + /** + * 网盘标识 + */ + private String panType; + + /** + * nfd下载链接(可能获取不到) + * note: 不是下载直链 + */ + private String parserUrl; + /** * 扩展参数 */ - private Map extParameters;; + private Map extParameters; public String getFileName() { return fileName; @@ -81,6 +92,15 @@ public class FileInfo { return this; } + public String getFileIcon() { + return fileIcon; + } + + public FileInfo setFileIcon(String fileIcon) { + this.fileIcon = fileIcon; + return this; + } + public Long getSize() { return size; } @@ -162,6 +182,24 @@ public class FileInfo { return this; } + public String getPanType() { + return panType; + } + + public FileInfo setPanType(String panType) { + this.panType = panType; + return this; + } + + public String getParserUrl() { + return parserUrl; + } + + public FileInfo setParserUrl(String parserUrl) { + this.parserUrl = parserUrl; + return this; + } + public Map getExtParameters() { return extParameters; } @@ -171,15 +209,6 @@ public class FileInfo { return this; } - public String getFileIcon() { - return fileIcon; - } - - public FileInfo setFileIcon(String fileIcon) { - this.fileIcon = fileIcon; - return this; - } - @Override public String toString() { return "FileInfo{" + diff --git a/parser/src/main/java/cn/qaiu/parser/IPanTool.java b/parser/src/main/java/cn/qaiu/parser/IPanTool.java index 1fefa93..bd75b71 100644 --- a/parser/src/main/java/cn/qaiu/parser/IPanTool.java +++ b/parser/src/main/java/cn/qaiu/parser/IPanTool.java @@ -27,7 +27,7 @@ public interface IPanTool { * 根据文件ID获取下载链接 * @return url */ - default Future parseById(String id) { + default Future parseById() { Promise promise = Promise.promise(); promise.complete(); return promise.future(); diff --git a/parser/src/main/java/cn/qaiu/parser/PanBase.java b/parser/src/main/java/cn/qaiu/parser/PanBase.java index d14d8b5..3ffca98 100644 --- a/parser/src/main/java/cn/qaiu/parser/PanBase.java +++ b/parser/src/main/java/cn/qaiu/parser/PanBase.java @@ -233,4 +233,8 @@ public abstract class PanBase implements IPanTool { } } + + protected String getDomainName(){ + return shareLinkInfo.getOtherParam().getOrDefault("domainName", "").toString(); + } } diff --git a/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java b/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java index 5f67ad4..6bc53a4 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/FjTool.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Base64; import java.util.List; import java.util.zip.GZIPInputStream; @@ -99,8 +100,6 @@ public class FjTool extends PanBase { .setTemplateParam("ts", tsEncode) .send().onSuccess(r0 -> { // 忽略res - // long nowTs0 = System.currentTimeMillis(); - String tsEncode0 = AESUtils.encrypt2Hex(Long.toString(nowTs)); // 第一次请求 获取文件信息 // POST https://api.feijipan.com/ws/recommend/list?devType=6&devModel=Chrome&extra=2&shareId=146731&type=0&offset=1&limit=60 client.postAbs(UriTemplate.of(FIRST_REQUEST_URL)) @@ -228,17 +227,46 @@ public class FjTool extends PanBase { list.forEach(item->{ JsonObject fileJson = (JsonObject) item; FileInfo fileInfo = new FileInfo(); - // 映射已知字段 + + // 映射已知字段fileInfo + String fileId = fileJson.getString("fileId"); + String userId = fileJson.getString("userId"); + + // 其他参数 + long nowTs2 = System.currentTimeMillis(); + String tsEncode2 = AESUtils.encrypt2Hex(Long.toString(nowTs2)); + String fidEncode = AESUtils.encrypt2Hex(fileId + "|" + userId); + String auth = AESUtils.encrypt2Hex(fileId + "|" + nowTs2); + + // 回传用到的参数 + //"fidEncode", paramJson.getString("fidEncode")) + //"uuid", paramJson.getString("uuid")) + //"ts", paramJson.getString("ts")) + //"auth", paramJson.getString("auth")) + //"shareId", paramJson.getString("shareId")) + JsonObject entries = JsonObject.of( + "fidEncode", fidEncode, + "uuid", uuid, + "ts", tsEncode2, + "auth", auth, + "shareId", shareId); + byte[] encode = Base64.getEncoder().encode(entries.encode().getBytes()); + String param = new String(encode); + + long fileSize = fileJson.getLong("fileSize") * 1024; fileInfo.setFileName(fileJson.getString("fileName")) .setFileId(fileJson.getString("fileId")) .setCreateTime(fileJson.getString("createTime")) .setFileType(fileJson.getString("fileType")) - .setSize(fileJson.getLong("fileSize")) - .setSizeStr(FileSizeConverter.convertToReadableSize(fileJson.getLong("fileSize"))) + .setSize(fileSize) + .setSizeStr(FileSizeConverter.convertToReadableSize(fileSize)) .setCreateBy(fileJson.getLong("userId").toString()) .setDownloadCount(fileJson.getInteger("fileDownloads")) .setCreateTime(fileJson.getString("updTime")) - .setFileIcon(fileJson.getString("fileIcon")); + .setFileIcon(fileJson.getString("fileIcon")) + .setPanType(shareLinkInfo.getType()) + .setParserUrl(String.format("%s/v2/redirectUrl/%s/%s", getDomainName(), + shareLinkInfo.getType(), param)); result.add(fileInfo); }); promise.complete(result); @@ -246,4 +274,34 @@ public class FjTool extends PanBase { }); return promise.future(); } + + @Override + public Future parseById() { + // 第二次请求 + JsonObject paramJson = (JsonObject)shareLinkInfo.getOtherParam().get("paramJson"); + +// clientNoRedirects.getAbs(UriTemplate.of(SECOND_REQUEST_URL)) +// .putHeaders(header) +// .setTemplateParam("fidEncode", fidEncode) +// .setTemplateParam("uuid", uuid) +// .setTemplateParam("ts", tsEncode2) +// .setTemplateParam("auth", auth) +// .setTemplateParam("dataKey", shareId) + + clientNoRedirects.getAbs(UriTemplate.of(SECOND_REQUEST_URL)) + .setTemplateParam("fidEncode", paramJson.getString("fidEncode")) + .setTemplateParam("uuid", paramJson.getString("uuid")) + .setTemplateParam("ts", paramJson.getString("ts")) + .setTemplateParam("auth", paramJson.getString("auth")) + .setTemplateParam("dataKey", paramJson.getString("shareId")) + .putHeaders(header).send().onSuccess(res2 -> { + MultiMap headers = res2.headers(); + if (!headers.contains("Location")) { + fail(SECOND_REQUEST_URL + " 未找到重定向URL: \n" + res2.headers()); + return; + } + promise.complete(headers.get("Location")); + }).onFailure(handleFail(SECOND_REQUEST_URL)); + return promise.future(); + } } diff --git a/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java b/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java index e409d10..8bf9f2e 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java @@ -13,9 +13,7 @@ import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; import io.vertx.uritemplate.UriTemplate; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import java.util.*; /** * 蓝奏云优享 @@ -130,7 +128,7 @@ public class IzTool extends PanBase { .putHeaders(header).send().onSuccess(res2 -> { MultiMap headers = res2.headers(); if (!headers.contains("Location")) { - fail(SECOND_REQUEST_URL + " 未找到重定向URL: \n" + res.headers()); + fail(SECOND_REQUEST_URL + " 未找到重定向URL: \n" + headers); return; } promise.complete(headers.get("Location")); @@ -161,17 +159,43 @@ public class IzTool extends PanBase { list.forEach(item->{ JsonObject fileJson = (JsonObject) item; FileInfo fileInfo = new FileInfo(); + // 映射已知字段 + String fileId = fileJson.getString("fileId"); + String userId = fileJson.getString("userId"); + + // 回传用到的参数 + //"fidEncode", paramJson.getString("fidEncode")) + //"uuid", paramJson.getString("uuid")) + //"ts", paramJson.getString("ts")) + //"auth", paramJson.getString("auth")) + //"shareId", paramJson.getString("shareId")) + String fidEncode = AESUtils.encrypt2HexIz(fileId + "|" + userId); + String auth = AESUtils.encrypt2HexIz(fileId + "|" + nowTs); + JsonObject entries = JsonObject.of( + "fidEncode", fidEncode, + "uuid", uuid, + "ts", tsEncode, + "auth", auth, + "shareId", shareId); + byte[] encode = Base64.getEncoder().encode(entries.encode().getBytes()); + String param = new String(encode); + + + long fileSize = fileJson.getLong("fileSize") * 1024; fileInfo.setFileName(fileJson.getString("fileName")) - .setFileId(fileJson.getString("fileId")) + .setFileId(fileId) .setCreateTime(fileJson.getString("createTime")) .setFileType(fileJson.getString("fileType")) - .setSize(fileJson.getLong("fileSize")) - .setSizeStr(FileSizeConverter.convertToReadableSize(fileJson.getLong("fileSize"))) + .setSize(fileSize) + .setSizeStr(FileSizeConverter.convertToReadableSize(fileSize)) .setCreateBy(fileJson.getLong("userId").toString()) .setDownloadCount(fileJson.getInteger("fileDownloads")) .setCreateTime(fileJson.getString("updTime")) - .setFileIcon(fileJson.getString("fileIcon")); + .setFileIcon(fileJson.getString("fileIcon")) + .setPanType(shareLinkInfo.getType()) + .setParserUrl(String.format("%s/v2/redirectUrl/%s/%s", getDomainName(), + shareLinkInfo.getType(), param)); result.add(fileInfo); }); promise.complete(result); @@ -179,4 +203,25 @@ public class IzTool extends PanBase { }); return promise.future(); } + + @Override + public Future parseById() { + // 第二次请求 + JsonObject paramJson = (JsonObject)shareLinkInfo.getOtherParam().get("paramJson"); + clientNoRedirects.getAbs(UriTemplate.of(SECOND_REQUEST_URL)) + .setTemplateParam("fidEncode", paramJson.getString("fidEncode")) + .setTemplateParam("uuid", paramJson.getString("uuid")) + .setTemplateParam("ts", paramJson.getString("ts")) + .setTemplateParam("auth", paramJson.getString("auth")) + .setTemplateParam("shareId", paramJson.getString("shareId")) + .putHeaders(header).send().onSuccess(res2 -> { + MultiMap headers = res2.headers(); + if (!headers.contains("Location")) { + fail(SECOND_REQUEST_URL + " 未找到重定向URL: \n" + res2.headers()); + return; + } + promise.complete(headers.get("Location")); + }).onFailure(handleFail(SECOND_REQUEST_URL)); + return promise.future(); + } } diff --git a/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java b/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java index bd84431..651a7f8 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/LzTool.java @@ -101,14 +101,12 @@ public class LzTool extends PanBase { } int startPos = index + jsTagStart.length(); int endPos = html.indexOf(jsTagEnd, startPos); - return html.substring(startPos, endPos).replaceAll("",""); + return html.substring(startPos, endPos).replaceAll("", ""); } private void getDownURL(String key, WebClient client, Map signMap) { MultiMap map = MultiMap.caseInsensitiveMultiMap(); - signMap.forEach((k, v) -> { - map.set(k, v.toString()); - }); + signMap.forEach((k, v) -> map.set(k, v.toString())); MultiMap headers = getHeaders(key); String url = SHARE_URL_PREFIX + "/ajaxm.php"; @@ -155,9 +153,7 @@ public class LzTool extends PanBase { Map data = CastUtil.cast(scriptObjectMirror.get("data")); System.out.println(data); MultiMap map = MultiMap.caseInsensitiveMultiMap(); - data.forEach((k, v) -> { - map.set(k, v.toString()); - }); + data.forEach((k, v) -> map.set(k, v.toString())); MultiMap headers = getHeaders(sUrl); String url = SHARE_URL_PREFIX + "/filemoreajax.php?file=" + data.get("fid"); @@ -185,12 +181,16 @@ public class LzTool extends PanBase { FileInfo fileInfo = new FileInfo(); String size = fileJson.getString("size"); Long sizeNum = FileSizeConverter.convertToBytes(size); + String panType = shareLinkInfo.getType(); + String id = fileJson.getString("id"); fileInfo.setFileName(fileJson.getString("name_all")) - .setFileId(fileJson.getString("id")) + .setFileId(id) .setCreateTime(fileJson.getString("time")) .setFileType(fileJson.getString("icon")) .setSizeStr(fileJson.getString("size")) - .setSize(sizeNum); + .setSize(sizeNum) + .setPanType(panType) + .setParserUrl(getDomainName() + "/d/" + panType + "/" + id); System.out.println(fileInfo); list.add(fileInfo); }); diff --git a/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java b/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java index 20a2a09..5d327a4 100644 --- a/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java +++ b/web-service/src/main/java/cn/qaiu/lz/web/controller/ParserApi.java @@ -16,17 +16,17 @@ import cn.qaiu.vx.core.annotaions.RouteHandler; import cn.qaiu.vx.core.annotaions.RouteMapping; import cn.qaiu.vx.core.enums.RouteMethod; import cn.qaiu.vx.core.util.AsyncServiceUtil; +import cn.qaiu.vx.core.util.ResponseUtil; import cn.qaiu.vx.core.util.SharedDataUtil; import io.vertx.core.Future; import io.vertx.core.Promise; import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.core.json.JsonObject; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; +import java.util.*; import java.util.stream.Collectors; @RouteHandler(value = "/v2", order = 10) @@ -103,6 +103,41 @@ public class ParserApi { public Future> getFileList(HttpServerRequest request, String pwd) { String url = URLParamUtil.parserParams(request); ParserCreate parserCreate = ParserCreate.fromShareUrl(url).setShareLinkInfoPwd(pwd); + String linkPrefix = SharedDataUtil.getJsonConfig("server").getString("domainName"); + parserCreate.getShareLinkInfo().getOtherParam().put("domainName", linkPrefix); return parserCreate.createTool().parseFileList(); } + + // 目录解析下载文件 + // @RouteMapping("/getFileDownUrl/:type/:param") + public Future getFileDownUrl(String type, String param) { + ParserCreate parserCreate = ParserCreate.fromType(type).shareKey("-") // shareKey not null + .setShareLinkInfoPwd("-"); + + if (param.isEmpty()) { + Promise promise = Promise.promise(); + promise.fail("下载参数为空"); + return promise.future(); + } + + String paramStr = new String(Base64.getDecoder().decode(param)); + ShareLinkInfo shareLinkInfo = parserCreate.getShareLinkInfo(); + shareLinkInfo.getOtherParam().put("paramJson", new JsonObject(paramStr)); + + // domainName + String linkPrefix = SharedDataUtil.getJsonConfig("server").getString("domainName"); + shareLinkInfo.getOtherParam().put("domainName", linkPrefix); + return parserCreate.createTool().parseById(); + } + + + @RouteMapping("/redirectUrl/:type/:param") + public Future redirectUrl(HttpServerResponse response, String type, String param) { + Promise promise = Promise.promise(); + + getFileDownUrl(type, param) + .onSuccess(res -> ResponseUtil.redirect(response, res)) + .onFailure(t -> promise.fail(t.fillInStackTrace())); + return promise.future(); + } }