mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2026-02-25 22:55:22 +00:00
接口重构
This commit is contained in:
@@ -1,80 +0,0 @@
|
||||
package cn.qaiu.lz.common.util;
|
||||
|
||||
import cn.qaiu.vx.core.util.CastUtil;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 奶牛快传解析工具
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
* @date 2023/4/21 21:19
|
||||
*/
|
||||
@Slf4j
|
||||
public class CowTool {
|
||||
/*
|
||||
First request:
|
||||
{
|
||||
"code": "0000",
|
||||
"message": "success",
|
||||
"data": {
|
||||
"guid": "e4f41b51-b5da-4f60-9312-37aa10c0aad7",
|
||||
"firstFile": {
|
||||
"id": "23861191276513345",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Then request:
|
||||
{
|
||||
"code": "0000",
|
||||
"message": "success",
|
||||
"tn": "TN:DE0E092E8A464521983780FBA21D0CD3",
|
||||
"data": {
|
||||
"downloadUrl": "https://download.cowcs.com..."
|
||||
}
|
||||
}
|
||||
*/
|
||||
public static String parse(String fullUrl) throws Exception {
|
||||
var uniqueUrl = fullUrl.substring(fullUrl.lastIndexOf('/') + 1);
|
||||
var baseUrl = "https://cowtransfer.com/core/api/transfer/share";
|
||||
var result = Jsoup
|
||||
.connect(baseUrl + "?uniqueUrl=" + uniqueUrl).ignoreContentType(true)
|
||||
.get()
|
||||
.text();
|
||||
var objectMapper = new ObjectMapper();
|
||||
Map<String, Object> map = objectMapper.readValue(result, new TypeReference<>() {
|
||||
});
|
||||
|
||||
if ("success".equals(map.get("message")) && map.containsKey("data")) {
|
||||
Map<String, Object> data = CastUtil.cast(map.get("data"));
|
||||
var guid = data.get("guid").toString();
|
||||
Map<String, Object> firstFile = CastUtil.cast(data.get("firstFile"));
|
||||
var fileId = firstFile.get("id").toString();
|
||||
var result2 = Jsoup
|
||||
.connect(baseUrl + "/download?transferGuid=" + guid + "&fileId=" + fileId)
|
||||
.ignoreContentType(true)
|
||||
.get()
|
||||
.text();
|
||||
Map<String, Object> map2 = objectMapper.readValue(result2, new TypeReference<>() {});
|
||||
|
||||
if ("success".equals(map2.get("message")) && map2.containsKey("data")) {
|
||||
Map<String, Object> data2 = CastUtil.cast(map2.get("data"));
|
||||
var downloadUrl = data2.get("downloadUrl").toString();
|
||||
if (StringUtils.isNotEmpty(downloadUrl)) {
|
||||
log.info("cow parse success: {}", downloadUrl);
|
||||
return downloadUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
log.info("Cow parse field------------->end");
|
||||
throw new Exception("Cow解析失败");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package cn.qaiu.lz.common.util;
|
||||
|
||||
import cn.qaiu.vx.core.util.VertxHolder;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.client.WebClient;
|
||||
import io.vertx.uritemplate.UriTemplate;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 移动云空间解析
|
||||
*/
|
||||
@Slf4j
|
||||
public class EcTool {
|
||||
private static final String SHARE_URL_PREFIX = "https://www.ecpan.cn/drive/fileextoverrid" +
|
||||
".do?chainUrlTemplate=https:%2F%2Fwww.ecpan" +
|
||||
".cn%2Fweb%2F%23%2FyunpanProxy%3Fpath%3D%252F%2523%252Fdrive%252Foutside&parentId=-1&data={dataKey}";
|
||||
|
||||
private static final String DOWNLOAD_REQUEST_URL = "https://www.ecpan.cn/drive/sharedownload.do";
|
||||
|
||||
public static final String EC_HOST = "www.ecpan.cn";
|
||||
|
||||
public static Future<String> parse(String dataKey) {
|
||||
Promise<String> promise = Promise.promise();
|
||||
WebClient client = WebClient.create(VertxHolder.getVertxInstance());
|
||||
// 第一次请求 获取文件信息
|
||||
client.getAbs(UriTemplate.of(SHARE_URL_PREFIX)).setTemplateParam("dataKey", dataKey).send().onSuccess(res -> {
|
||||
JsonObject jsonObject = res.bodyAsJsonObject();
|
||||
log.debug("ecPan get file info -> {}", jsonObject);
|
||||
JsonObject fileInfo = jsonObject
|
||||
.getJsonObject("var")
|
||||
.getJsonObject("chainFileInfo");
|
||||
if (!fileInfo.containsKey("errMesg")) {
|
||||
JsonObject cloudpFile = fileInfo.getJsonObject("cloudpFile");
|
||||
JsonArray fileIdList = JsonArray.of(cloudpFile);
|
||||
// 构造请求JSON {"extCodeFlag":0,"isIp":0}
|
||||
JsonObject requestBodyJson = JsonObject.of("extCodeFlag", 0, "isIp", 0);
|
||||
requestBodyJson.put("shareId", Integer.parseInt(fileInfo.getString("shareId"))); // 注意shareId
|
||||
// 数据类型
|
||||
requestBodyJson.put("groupId", cloudpFile.getString("groupId"));
|
||||
requestBodyJson.put("fileIdList", fileInfo.getJsonArray("cloudpFileList"));
|
||||
|
||||
// 第二次请求 获取下载链接
|
||||
client.postAbs(DOWNLOAD_REQUEST_URL)
|
||||
.sendJsonObject(requestBodyJson).onSuccess(res2 -> {
|
||||
JsonObject jsonRes = res2.bodyAsJsonObject();
|
||||
log.debug("ecPan get download url -> {}", res2.body().toString());
|
||||
promise.complete(jsonRes.getJsonObject("var").getString("downloadUrl"));
|
||||
}).onFailure(t -> {
|
||||
promise.fail(new RuntimeException("解析异常: key = " + dataKey, t.fillInStackTrace()));
|
||||
});
|
||||
|
||||
} else {
|
||||
promise.fail(new RuntimeException(DOWNLOAD_REQUEST_URL + " 解析失败: "
|
||||
+ fileInfo.getString("errMesg")) + " key = " + dataKey);
|
||||
}
|
||||
}
|
||||
).onFailure(t -> {
|
||||
promise.fail(new RuntimeException("解析异常: key = " + dataKey, t.fillInStackTrace()));
|
||||
});
|
||||
return promise.future();
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
package cn.qaiu.lz.common.util;
|
||||
|
||||
import cn.qaiu.vx.core.util.VertxHolder;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.MultiMap;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.buffer.Buffer;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.client.HttpResponse;
|
||||
import io.vertx.ext.web.client.WebClient;
|
||||
import io.vertx.ext.web.client.WebClientOptions;
|
||||
import io.vertx.ext.web.client.WebClientSession;
|
||||
import io.vertx.uritemplate.UriTemplate;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 亿方云
|
||||
*/
|
||||
public class FcTool {
|
||||
|
||||
public static final String SHARE_URL_PREFIX = "https://v2.fangcloud.com/sharing/";
|
||||
public static final String SHARE_URL_PREFIX2 = "https://v2.fangcloud.cn/sharing/";
|
||||
private static final String DOWN_REQUEST_URL = "https://v2.fangcloud.cn/apps/files/download?file_id={fid}" +
|
||||
"&scenario=share&unique_name={uname}";
|
||||
|
||||
public static Future<String> parse(String data, String code) {
|
||||
String dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, data);
|
||||
|
||||
Promise<String> promise = Promise.promise();
|
||||
|
||||
Vertx vertx = VertxHolder.getVertxInstance();
|
||||
WebClient client = WebClient.create(vertx);
|
||||
WebClientSession sClient = WebClientSession.create(client);
|
||||
// 第一次请求 自动重定向
|
||||
sClient.getAbs(SHARE_URL_PREFIX + dataKey).send().onSuccess(res -> {
|
||||
|
||||
// 判断是否是加密分享
|
||||
if (StringUtils.isNotEmpty(code)) {
|
||||
// 获取requesttoken
|
||||
String html = res.bodyAsString();
|
||||
Pattern compile = Pattern.compile("name=\"requesttoken\"\\s+value=\"([a-zA-Z0-9_+=]+)\"");
|
||||
Matcher matcher = compile.matcher(html);
|
||||
if (!matcher.find()) {
|
||||
promise.fail(SHARE_URL_PREFIX + " 未匹配到加密分享的密码输入页面的requesttoken: \n" + html);
|
||||
return;
|
||||
}
|
||||
String token = matcher.group(1);
|
||||
|
||||
sClient.postAbs(SHARE_URL_PREFIX2 + dataKey).sendForm(MultiMap.caseInsensitiveMultiMap()
|
||||
.set("requesttoken", token)
|
||||
.set("password", code)).onSuccess(res2 -> {
|
||||
if (res2.statusCode() == 302) {
|
||||
sClient.getAbs(res2.getHeader("Location")).send().onSuccess(res3 -> {
|
||||
getDownURL(dataKey, promise, res3, sClient);
|
||||
});
|
||||
} else {
|
||||
promise.fail(SHARE_URL_PREFIX + " 密码跳转后获取重定向失败 \n" + html);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
getDownURL(dataKey, promise, res, sClient);
|
||||
});
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
private static void getDownURL(String dataKey, Promise<String> promise, HttpResponse<Buffer> res,
|
||||
WebClientSession sClient) {
|
||||
// 从HTML中找到文件id
|
||||
String html = res.bodyAsString();
|
||||
Pattern compile = Pattern.compile("id=\"typed_id\"\\s+value=\"file_(\\d+)\"");
|
||||
Matcher matcher = compile.matcher(html);
|
||||
if (!matcher.find()) {
|
||||
promise.fail(SHARE_URL_PREFIX + " 未匹配到文件id(typed_id): \n" + html);
|
||||
return;
|
||||
}
|
||||
String fid = matcher.group(1);
|
||||
|
||||
// 创建一个不自动重定向的WebClientSession
|
||||
WebClient clientNoRedirects = WebClient.create(VertxHolder.getVertxInstance(),
|
||||
new WebClientOptions().setFollowRedirects(false));
|
||||
WebClientSession sClientNoRedirects = WebClientSession.create(clientNoRedirects, sClient.cookieStore());
|
||||
// 第二次请求
|
||||
sClientNoRedirects.getAbs(UriTemplate.of(DOWN_REQUEST_URL))
|
||||
.setTemplateParam("fid", fid)
|
||||
.setTemplateParam("unique_name", dataKey).send().onSuccess(res2 -> {
|
||||
JsonObject resJson;
|
||||
try {
|
||||
resJson = res2.bodyAsJsonObject();
|
||||
} catch (Exception e) {
|
||||
promise.fail(DOWN_REQUEST_URL + " 第二次请求没有返回JSON, 可能下载受限: " + res2.bodyAsString());
|
||||
return;
|
||||
}
|
||||
if (!resJson.getBoolean("success")) {
|
||||
promise.fail(DOWN_REQUEST_URL + " 第二次请求未得到正确相应: " + resJson);
|
||||
return;
|
||||
}
|
||||
promise.complete(resJson.getString("download_url"));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package cn.qaiu.lz.common.util;
|
||||
|
||||
import cn.qaiu.vx.core.util.VertxHolder;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.MultiMap;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.client.WebClient;
|
||||
import io.vertx.ext.web.client.WebClientOptions;
|
||||
import io.vertx.uritemplate.UriTemplate;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 小飞机网盘
|
||||
*
|
||||
* @version V016_230609
|
||||
*/
|
||||
public class FjTool {
|
||||
|
||||
public static final String SHARE_URL_PREFIX = "https://www.feijix.com/s/";
|
||||
private static final String API_URL_PREFIX = "https://api.feijipan.com/ws/";
|
||||
|
||||
private static final String FIRST_REQUEST_URL = API_URL_PREFIX + "recommend/list?devType=6&devModel=Chrome&extra" +
|
||||
"=2&shareId={shareId}&type=0&offset=1&limit=60";
|
||||
|
||||
private static final String SECOND_REQUEST_URL = API_URL_PREFIX + "file/redirect?downloadId={fidEncode}&enable=1" +
|
||||
"&devType=6&uuid={uuid}×tamp={ts}&auth={auth}";
|
||||
|
||||
public static Future<String> parse(String data) {
|
||||
String dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, data);
|
||||
|
||||
Promise<String> promise = Promise.promise();
|
||||
WebClient client = WebClient.create(VertxHolder.getVertxInstance(),
|
||||
new WebClientOptions().setFollowRedirects(false));
|
||||
String shareId = String.valueOf(AESUtils.idEncrypt(dataKey));
|
||||
|
||||
// 第一次请求 获取文件信息
|
||||
// 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)).setTemplateParam("shareId", shareId).send().onSuccess(res -> {
|
||||
JsonObject resJson = res.bodyAsJsonObject();
|
||||
if (resJson.getInteger("code") != 200) {
|
||||
promise.fail(FIRST_REQUEST_URL + " 返回异常: " + resJson);
|
||||
return;
|
||||
}
|
||||
if (resJson.getJsonArray("list").size() == 0) {
|
||||
promise.fail(FIRST_REQUEST_URL + " 解析文件列表为空: " + resJson);
|
||||
return;
|
||||
}
|
||||
// 文件Id
|
||||
String fileId = resJson.getJsonArray("list").getJsonObject(0).getString("fileIds");
|
||||
// 其他参数
|
||||
long nowTs = System.currentTimeMillis();
|
||||
String tsEncode = AESUtils.encrypt2Hex(Long.toString(nowTs));
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
String fidEncode = AESUtils.encrypt2Hex(fileId + "|");
|
||||
String auth = AESUtils.encrypt2Hex(fileId + "|" + nowTs);
|
||||
// 第二次请求
|
||||
client.getAbs(UriTemplate.of(SECOND_REQUEST_URL))
|
||||
.setTemplateParam("fidEncode", fidEncode)
|
||||
.setTemplateParam("uuid", uuid)
|
||||
.setTemplateParam("ts", tsEncode)
|
||||
.setTemplateParam("auth", auth).send().onSuccess(res2 -> {
|
||||
MultiMap headers = res2.headers();
|
||||
if (!headers.contains("Location")) {
|
||||
promise.fail(SECOND_REQUEST_URL + " 未找到重定向URL: \n" + res.headers());
|
||||
return;
|
||||
}
|
||||
promise.complete(headers.get("Location"));
|
||||
});
|
||||
});
|
||||
|
||||
return promise.future();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package cn.qaiu.lz.common.util;
|
||||
|
||||
public interface IFuturePanTool {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package cn.qaiu.lz.common.util;
|
||||
|
||||
import cn.qaiu.vx.core.util.VertxHolder;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.MultiMap;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.client.WebClient;
|
||||
import io.vertx.ext.web.client.WebClientOptions;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 蓝奏云解析工具
|
||||
*
|
||||
* @author QAIU
|
||||
* @version 1.0 update 2021/5/16 10:39
|
||||
*/
|
||||
public class LzTool {
|
||||
|
||||
public static final String SHARE_URL_PREFIX = "https://wwwa.lanzoui.com";
|
||||
|
||||
public static Future<String> parse(String data, String code) {
|
||||
Promise<String> promise = Promise.promise();
|
||||
String key = data.indexOf('/') > 0 ? data : SHARE_URL_PREFIX + "/" + data;
|
||||
|
||||
WebClient client = WebClient.create(VertxHolder.getVertxInstance(),
|
||||
new WebClientOptions().setFollowRedirects(false));
|
||||
client.getAbs(key).send().onSuccess(res -> {
|
||||
String html = res.bodyAsString();
|
||||
// 匹配iframe
|
||||
Pattern compile = Pattern.compile("src=\"(/fn\\?[a-zA-Z0-9_+/=]{16,})\"");
|
||||
Matcher matcher = compile.matcher(html);
|
||||
if (!matcher.find()) {
|
||||
// 没有Iframe说明是加密分享, 匹配sign通过密码请求下载页面
|
||||
Pattern compile2 = Pattern.compile("sign=([0-9a-zA-Z_]{16,})");
|
||||
Matcher matcher2 = compile2.matcher(html);
|
||||
if (!matcher2.find()) {
|
||||
promise.fail(key + ": sign正则匹配失败, 可能分享已失效: " + html);
|
||||
return;
|
||||
}
|
||||
String sign = matcher2.group(1);
|
||||
getDownURL(promise, code, key, client, sign);
|
||||
return;
|
||||
}
|
||||
String iframePath = matcher.group(1);
|
||||
client.getAbs(SHARE_URL_PREFIX + iframePath).send().onSuccess(res2 -> {
|
||||
String html2 = res2.bodyAsString();
|
||||
System.out.println(html);
|
||||
Matcher matcher2 = Pattern.compile("'sign'\s*:\s*'([0-9a-zA-Z_]+)'").matcher(html2);
|
||||
if (!matcher2.find()) {
|
||||
promise.fail(SHARE_URL_PREFIX + iframePath + " -> " + key + ": sign正则匹配失败, 可能分享已失效: " + html2);
|
||||
return;
|
||||
}
|
||||
String sign = matcher2.group(1);
|
||||
getDownURL(promise, code, key, client, sign);
|
||||
});
|
||||
});
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
private static void getDownURL(Promise<String> promise, String code, String key, WebClient client, String sign) {
|
||||
MultiMap headers = MultiMap.caseInsensitiveMultiMap();
|
||||
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";
|
||||
headers.set("User-Agent", userAgent2);
|
||||
headers.set("referer", key);
|
||||
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.postAbs(SHARE_URL_PREFIX + "/ajaxm.php").putHeaders(headers).sendForm(MultiMap
|
||||
.caseInsensitiveMultiMap()
|
||||
.set("action", "downprocess")
|
||||
.set("sign", sign).set("p", code)).onSuccess(res2 -> {
|
||||
JsonObject urlJson = res2.bodyAsJsonObject();
|
||||
if (urlJson.getInteger("zt") != 1) {
|
||||
promise.fail(urlJson.getString("inf"));
|
||||
return;
|
||||
}
|
||||
String downUrl = urlJson.getString("dom") + "/file/" + urlJson.getString("url");
|
||||
client.getAbs(downUrl).putHeaders(headers).send().onSuccess(res3 -> {
|
||||
promise.complete(res3.headers().get("Location"));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package cn.qaiu.lz.common.util;
|
||||
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.Promise;
|
||||
|
||||
public class QkTool {
|
||||
public static Future<String> parse(String data, String code) {
|
||||
Promise<String> promise = Promise.promise();
|
||||
|
||||
return promise.future();
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package cn.qaiu.lz.common.util;
|
||||
|
||||
import cn.qaiu.vx.core.util.VertxHolder;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.client.WebClient;
|
||||
import io.vertx.uritemplate.UriTemplate;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 移动云空间解析
|
||||
*/
|
||||
@Slf4j
|
||||
public class UcTool {
|
||||
private static final String API_URL_PREFIX = "https://pc-api.uc.cn/1/clouddrive/";
|
||||
|
||||
public static final String SHARE_URL_PREFIX = "https://fast.uc.cn/s/";
|
||||
|
||||
private static final String FIRST_REQUEST_URL = API_URL_PREFIX + "share/sharepage/token?entry=ft&fr=pc&pr" +
|
||||
"=UCBrowser";
|
||||
|
||||
private static final String SECOND_REQUEST_URL = API_URL_PREFIX + "transfer_share/detail?pwd_id={pwd_id}&passcode" +
|
||||
"={passcode}&stoken={stoken}";
|
||||
|
||||
private static final String THIRD_REQUEST_URL = API_URL_PREFIX + "file/download?entry=ft&fr=pc&pr=UCBrowser";
|
||||
|
||||
public static Future<String> parse(String data, String code) {
|
||||
var dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, data);
|
||||
var passcode = (code == null) ? "" : code;
|
||||
Promise<String> promise = Promise.promise();
|
||||
var client = WebClient.create(VertxHolder.getVertxInstance());
|
||||
var jsonObject = JsonObject.of("share_for_transfer", true);
|
||||
jsonObject.put("pwd_id", dataKey);
|
||||
jsonObject.put("passcode", passcode);
|
||||
// 第一次请求 获取文件信息
|
||||
client.postAbs(FIRST_REQUEST_URL).sendJsonObject(jsonObject).onSuccess(res -> {
|
||||
log.debug("第一阶段 {}", res.body());
|
||||
var resJson = res.bodyAsJsonObject();
|
||||
if (resJson.getInteger("code") != 0) {
|
||||
promise.fail(FIRST_REQUEST_URL + " 返回异常: " + resJson);
|
||||
return;
|
||||
}
|
||||
var stoken = resJson.getJsonObject("data").getString("stoken");
|
||||
// 第二次请求
|
||||
client.getAbs(UriTemplate.of(SECOND_REQUEST_URL))
|
||||
.setTemplateParam("pwd_id", dataKey)
|
||||
.setTemplateParam("passcode", passcode)
|
||||
.setTemplateParam("stoken", stoken)
|
||||
.send().onSuccess(res2 -> {
|
||||
log.debug("第二阶段 {}", res2.body());
|
||||
JsonObject resJson2 = res2.bodyAsJsonObject();
|
||||
if (resJson2.getInteger("code") != 0) {
|
||||
promise.fail(FIRST_REQUEST_URL + " 返回异常: " + resJson2);
|
||||
return;
|
||||
}
|
||||
// 文件信息
|
||||
var info = resJson2.getJsonObject("data").getJsonArray("list").getJsonObject(0);
|
||||
// 第二次请求
|
||||
var bodyJson = JsonObject.of()
|
||||
.put("fids", JsonArray.of(info.getString("fid")))
|
||||
.put("pwd_id", dataKey)
|
||||
.put("stoken", stoken)
|
||||
.put("fids_token", JsonArray.of(info.getString("share_fid_token")));
|
||||
client.postAbs(THIRD_REQUEST_URL).sendJsonObject(bodyJson)
|
||||
.onSuccess(res3 -> {
|
||||
log.debug("第三阶段 {}", res3.body());
|
||||
var resJson3 = res3.bodyAsJsonObject();
|
||||
if (resJson3.getInteger("code") != 0) {
|
||||
promise.fail(FIRST_REQUEST_URL + " 返回异常: " + resJson2);
|
||||
return;
|
||||
}
|
||||
promise.complete(resJson3.getJsonArray("data").getJsonObject(0).getString("download_url"));
|
||||
})
|
||||
.onFailure(t -> promise
|
||||
.fail(new RuntimeException("解析异常: ", t.fillInStackTrace())));
|
||||
|
||||
}).onFailure(t -> promise.fail(new RuntimeException("解析异常: ", t.fillInStackTrace())));
|
||||
}
|
||||
).onFailure(t -> promise.fail(new RuntimeException("解析异常: key = " + dataKey, t.fillInStackTrace())));
|
||||
return promise.future();
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package cn.qaiu.lz.common.util;
|
||||
|
||||
import cn.qaiu.vx.core.util.VertxHolder;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.client.WebClient;
|
||||
import io.vertx.uritemplate.UriTemplate;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 123网盘
|
||||
*/
|
||||
public class YeTool {
|
||||
public static final String SHARE_URL_PREFIX = "https://www.123pan.com/s/";
|
||||
public static final String FIRST_REQUEST_URL = SHARE_URL_PREFIX + "{key}.html";
|
||||
private static final String GET_FILE_INFO_URL = "https://www.123pan.com/a/api/share/get?limit=100&next=1&orderBy" +
|
||||
"=file_name&orderDirection=asc&shareKey={shareKey}&SharePwd={pwd}&ParentFileId=0&Page=1&event" +
|
||||
"=homeListFile&operateType=1";
|
||||
|
||||
public static Future<String> parse(String data, String code) {
|
||||
|
||||
String dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, data);
|
||||
Promise<String> promise = Promise.promise();
|
||||
WebClient client = WebClient.create(VertxHolder.getVertxInstance());
|
||||
|
||||
client.getAbs(UriTemplate.of(FIRST_REQUEST_URL)).setTemplateParam("key", dataKey).send().onSuccess(res -> {
|
||||
|
||||
String html = res.bodyAsString();
|
||||
Pattern compile = Pattern.compile("window.g_initialProps\\s*=\\s*(.*);");
|
||||
Matcher matcher = compile.matcher(html);
|
||||
|
||||
if (!matcher.find()) {
|
||||
System.out.println("err");
|
||||
return;
|
||||
}
|
||||
String fileInfoString = matcher.group(1);
|
||||
JsonObject fileInfoJson = new JsonObject(fileInfoString);
|
||||
JsonObject resJson = fileInfoJson.getJsonObject("res");
|
||||
JsonObject resListJson = fileInfoJson.getJsonObject("reslist");
|
||||
|
||||
if (resJson == null || resJson.getInteger("code") != 0) {
|
||||
promise.fail(dataKey + " 解析到异常JSON: "+resJson);
|
||||
return;
|
||||
}
|
||||
String shareKey = resJson.getJsonObject("data").getString("ShareKey");
|
||||
if (resListJson == null || resListJson.getInteger("code") != 0) {
|
||||
// 加密分享
|
||||
if (StringUtils.isNotEmpty(code)) {
|
||||
client.getAbs(UriTemplate.of(GET_FILE_INFO_URL))
|
||||
.setTemplateParam("shareKey", shareKey)
|
||||
.setTemplateParam("pwd", code)
|
||||
.send().onSuccess(res2 -> {
|
||||
JsonObject infoJson = res2.bodyAsJsonObject();
|
||||
if (infoJson.getInteger("code") != 0) {
|
||||
return;
|
||||
}
|
||||
JsonObject getFileInfoJson =
|
||||
infoJson.getJsonObject("data").getJsonArray("InfoList").getJsonObject(0);
|
||||
getFileInfoJson.put("ShareKey", shareKey);
|
||||
getDownUrl(promise, client, getFileInfoJson);
|
||||
});
|
||||
} else {
|
||||
promise.fail(dataKey + " 该分享需要密码");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
JsonObject reqBodyJson = resListJson.getJsonObject("data").getJsonArray("InfoList").getJsonObject(0);
|
||||
reqBodyJson.put("ShareKey", shareKey);
|
||||
getDownUrl(promise, client, reqBodyJson);
|
||||
});
|
||||
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
private static void getDownUrl(Promise<String> promise, WebClient client, JsonObject reqBodyJson) {
|
||||
System.out.println(reqBodyJson);
|
||||
client.postAbs("https://www.123pan.com/a/api/share/download/info").sendJsonObject(reqBodyJson).onSuccess(res2 -> {
|
||||
JsonObject downURLJson = res2.bodyAsJsonObject();
|
||||
System.out.println(downURLJson);
|
||||
if (downURLJson.getInteger("code") != 0) {
|
||||
return;
|
||||
}
|
||||
String downURL = downURLJson.getJsonObject("data").getString("DownloadURL");
|
||||
try {
|
||||
Map<String, String> urlParams = CommonUtils.getURLParams(downURL);
|
||||
String params = urlParams.get("params");
|
||||
byte[] decodeByte = Base64.getDecoder().decode(params);
|
||||
promise.complete(new String(decodeByte));
|
||||
} catch (MalformedURLException e) {
|
||||
promise.fail("urlParams解析异常" + e.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user