1. P115网盘解析BUG

2. 完善onedrive支持
This commit is contained in:
QAIU
2024-12-16 15:54:06 +08:00
parent f8d2426ff6
commit 693a4f0f63
2 changed files with 212 additions and 21 deletions

View File

@@ -67,9 +67,9 @@ public class P115Tool extends PanBase {
// 第二次请求
// share_code={dataKey}&receive_code={dataPwd}&file_id={file_id}
clientNoRedirects.postAbs(SECOND_REQUEST_URL)
client.postAbs(SECOND_REQUEST_URL)
.putHeaders(header)
.putHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
.sendForm(MultiMap.caseInsensitiveMultiMap()
.set("share_code", shareLinkInfo.getShareKey())
.set("receive_code", shareLinkInfo.getSharePassword())

View File

@@ -1,10 +1,21 @@
package cn.qaiu.parser.impl;
import cn.qaiu.WebClientVertxInit;
import cn.qaiu.entity.ShareLinkInfo;
import cn.qaiu.parser.PanBase;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.WorkerExecutor;
import io.vertx.core.json.JsonObject;
import io.vertx.core.net.ProxyOptions;
import io.vertx.uritemplate.UriTemplate;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -21,40 +32,208 @@ public class PodTool extends PanBase {
* -> @content.downloadUrl
*/
private static final String api = "https://api.onedrive.com/v1.0/drives/{cid}/items/{cid20}?authkey={authkey}";
// https://onedrive.live.com/redir?resid=ABFD0A26E47D3458!4699&e=OggA4s&migratedtospo=true&redeem=aHR0cHM6Ly8xZHJ2Lm1zL3UvcyFBbGcwZmVRbUN2MnJwRnZ1NDQ0aGc1eVZxRGNLP2U9T2dnQTRz
private static final String API_TEMPLATE = "https://onedrive.live.com/embed" +
"?id={resid}&resid={resid1}" +
"&cid={cid}" +
"&redeem={redeem}" +
"&migratedtospo=true&embed=1";
private static final String TOKEN_API = "https://api-badgerp.svc.ms/v1.0/token";
private static final Pattern redirectUrlRegex =
Pattern.compile("=(?<cid>.+)!(?<cid2>.+)&authkey=(?<authkey>.+)&e=(?<e>.+)");
Pattern.compile("resid=(?<cid1>[^!]+)!(?<cid2>[^&]+).+&redeem=(?<redeem>.+).*");
public PodTool(ShareLinkInfo shareLinkInfo) {
super(shareLinkInfo);
}
public Future<String> parse() {
clientNoRedirects.getAbs(shareLinkInfo.getShareUrl()).send().onSuccess(r0 -> {
/*
* POST https://api-badgerp.svc.ms/v1.0/token
* Content-Type: application/json
*
* {
* "appid": "00000000-0000-0000-0000-0000481710a4"
* }
*/
// https://my.microsoftpersonalcontent.com/_api/v2.0/shares/u!aHR0cHM6Ly8xZHJ2Lm1zL3UvcyFBbGcwZmVRbUN2MnJwRnZ1NDQ0aGc1eVZxRGNLP2U9T2dnQTRz/driveitem?%24select=*%2Cocr%2CwebDavUrl
// https://onedrive.live.com/embed?id=ABFD0A26E47D3458!4698&resid=ABFD0A26E47D3458!4698&cid=abfd0a26e47d3458&redeem=aHR0cHM6Ly8xZHJ2Lm1zL3UvYy9hYmZkMGEyNmU0N2QzNDU4L0lRUllOSDNrSmdyOUlJQ3JXaElBQUFBQUFTWGlubWZ2WmNxYUQyMXJUQjIxVmg4&migratedtospo=true&embed=1
clientNoRedirects.getAbs(shareLinkInfo.getShareUrl() == null ? shareLinkInfo.getStandardUrl() :
shareLinkInfo.getShareUrl()).send().onSuccess(r0 -> {
String location = r0.getHeader("Location");
Matcher matcher = redirectUrlRegex.matcher(location);
if (matcher.find()) {
var cid= matcher.group("cid");
var cid2= matcher.group("cid2");
var authkey= matcher.group("authkey");
client.getAbs(UriTemplate.of(api))
.setTemplateParam("cid", cid)
.setTemplateParam("cid20", cid + "!" + cid2)
.setTemplateParam("authkey", authkey).send()
.onSuccess(res -> {
JsonObject jsonObject = asJson(res);
// System.out.println(jsonObject);
complete(jsonObject.getString("@content.downloadUrl"));
})
.onFailure(handleFail());
if (!matcher.find()) {
fail("Location格式错误");
return;
}
String redeem = matcher.group("redeem");
String cid1 = matcher.group("cid1");
String cid2 = cid1 + "!" + matcher.group("cid2");
clientNoRedirects.getAbs(UriTemplate.of(API_TEMPLATE))
.setTemplateParam("resid", cid2)
.setTemplateParam("resid1", cid2)
.setTemplateParam("cid", cid1.toLowerCase())
.setTemplateParam("redeem", redeem)
.proxy(new ProxyOptions().setHost("127.0.0.1").setPort(7890))
.send()
.onSuccess(r1 -> {
String auth =
r1.cookies().stream().filter(c -> c.startsWith("BadgerAuth=")).findFirst().orElse("");
if (auth.isEmpty()) {
fail("Error BadgerAuth not fount");
return;
}
String token = auth.split(";")[0].split("=")[1];
try {
String url = matcherUrl(r1.bodyAsString());
sendHttpRequest(url, token).onSuccess(body -> {
Matcher matcher1 =
Pattern.compile("\"downloadUrl\":\"(?<url>https?://[^\s\"]+)").matcher(body);
if (matcher1.find()) {
complete(matcher1.group("url"));
} else {
fail();
}
}).onFailure(handleFail());
} catch (Exception ignored) {
sendHttpRequest2(token, redeem).onSuccess(res -> {
try {
complete(new JsonObject(res).getString("@content.downloadUrl"));
} catch (Exception ignored1) {
fail();
}
}).onFailure(handleFail());
}
}).onFailure(handleFail());
}).onFailure(handleFail());
return promise.future();
}
private String matcherUrl(String html) {
// 正则表达式来匹配 URL
String urlRegex = "'action'.+(?<url>https://.+)'\\)";
Pattern urlPattern = Pattern.compile(urlRegex);
Matcher urlMatcher = urlPattern.matcher(html);
if (urlMatcher.find()) {
String url = urlMatcher.group("url");
System.out.println("URL: " + url);
return url;
}
throw new RuntimeException("URL匹配失败");
}
private String matcherToken(String html) {
// 正则表达式来匹配 inputElem.value 中的 Token
String tokenRegex = "inputElem\\.value\\s*=\\s*'([^']+)'";
Pattern tokenPattern = Pattern.compile(tokenRegex);
Matcher tokenMatcher = tokenPattern.matcher(html);
if (tokenMatcher.find()) {
String token = tokenMatcher.group(1);
System.out.println("Token: " + token);
return token;
}
throw new RuntimeException("token匹配失败");
}
public Future<String> sendHttpRequest2(String token, String redeem) {
Promise<String> promise = Promise.promise();
// 构造 HttpClient
HttpClient client = HttpClient.newHttpClient();
// 构造请求的 URI 和头部信息
// https://onedrive.live.com/redir?cid=abfd0a26e47d3458&resid=ABFD0A26E47D3458!4465&ithint=file%2cxlsx&e=Ao2uSU&migratedtospo=true&redeem=aHR0cHM6Ly8xZHJ2Lm1zL3gvYy9hYmZkMGEyNmU0N2QzNDU4L0VWZzBmZVFtQ3YwZ2dLdHhFUUFBQUFBQlRQRWVDMTZfZk1EYk5FTjhEdTRta1E_ZT1BbzJ1U1U
String url = ("https://my.microsoftpersonalcontent.com/_api/v2.0/shares/u!%s/driveItem?$select=content" +
".downloadUrl").formatted(redeem);
String authorizationHeader = "Badger " + token;
// 构建请求
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", authorizationHeader)
.build();
// 发送请求并处理响应
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(response -> {
System.out.println("Response Status Code: " + response.statusCode());
System.out.println("Response Body: " + response.body());
promise.complete(response.body());
return null;
});
return promise.future();
}
public Future<String> sendHttpRequest(String url, String token) {
// 创建一个 WorkerExecutor 用于异步执行阻塞的 HTTP 请求
WorkerExecutor executor = WebClientVertxInit.get().createSharedWorkerExecutor("http-client-worker");
Promise<String> promise = Promise.promise();
executor.executeBlocking(() -> {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = null;
try {
// 构造请求
request = HttpRequest.newBuilder()
.uri(new URI(url))
.header("accept", "text/html,application/xhtml+xml,application/xml;q=0.9," +
"image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;" +
"v=b3;q=0.7")
.header("accept-language", "zh-CN,zh;q=0.9")
.header("cache-control", "no-cache")
.header("content-type", "application/x-www-form-urlencoded")
.header("dnt", "1")
.header("origin", "https://onedrive.live.com")
.header("pragma", "no-cache")
.header("priority", "u=0, i")
.header("referer", "https://onedrive.live.com/")
.header("sec-ch-ua", "\"Chromium\";v=\"130\", \"Google Chrome\";v=\"130\", " +
"\"Not?A_Brand\";v=\"99\"")
.header("sec-ch-ua-mobile", "?0")
.header("sec-ch-ua-platform", "\"Windows\"")
.header("sec-fetch-dest", "iframe")
.header("sec-fetch-mode", "navigate")
.header("sec-fetch-site", "cross-site")
.header("upgrade-insecure-requests", "1")
.header("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537" +
".36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36")
.POST(HttpRequest.BodyPublishers.ofString("badger_token=" + token))
.build();
// 发起请求并获取响应
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
// 返回响应体
promise.complete(response.body());
return null;
} catch (URISyntaxException | IOException | InterruptedException e) {
throw new RuntimeException(e);
}
});
return promise.future();
}
//https://onedrive.live.com/redir?resid=ABFD0A26E47D3458!4699&e=OggA4s&migratedtospo=true&redeem=aHR0cHM6Ly8xZHJ2Lm1zL3UvcyFBbGcwZmVRbUN2MnJwRnZ1NDQ0aGc1eVZxRGNLP2U9T2dnQTRz
// public static void main(String[] args) {
public static void main(String[] args) {
// Matcher matcher = redirectUrlRegex.matcher("https://onedrive.live.com/redir?resid=ABFD0A26E47D3458!4698" +
// "&authkey=!ACpvXghP5xhG_cg&e=hV98W1");
// if (matcher.find()) {
@@ -62,6 +241,18 @@ public class PodTool extends PanBase {
// System.out.println(matcher.group("cid2"));
// System.out.println(matcher.group("authkey"));
// }
// appid 5cbed6ac-a083-4e14-b191-b4ba07653de2 5cbed6ac-a083-4e14-b191-b4ba07653de2
// https://my.microsoftpersonalcontent.com/personal/abfd0a26e47d3458/_layouts/15/embed.aspx?UniqueId=e47d3458-0a26-20fd-80ab-5b1200000000&Translate=false&ApiVersion=2.0
// https://my.microsoftpersonalcontent.com/personal/abfd0a26e47d3458/_layouts/15/embed.aspx?UniqueId=6b0900d6-abcf-44ce-b7bf-7b626bcbe4b8&Translate=false&ApiVersion=2.0
// https://1drv.ms/u/s!Alg0feQmCv2rpFvu444hg5yVqDcK?e=OggA4s
// https://1drv.ms/u/c/abfd0a26e47d3458/EVg0feQmCv0ggKtbEgAAAAABqGv8K6HmOwLRsvokyV5fUg?e=iqoRc0
// https://1drv.ms/u/c/abfd0a26e47d3458/EVg0feQmCv0ggKtaEgAAAAAB-lF1qjkfv5OqdrT9VSMDMw
new PodTool(ShareLinkInfo.newBuilder().shareUrl("https://1drv.ms/x/c/abfd0a26e47d3458" +
"/EVg0feQmCv0ggKtxEQAAAAABTPEeC16_fMDbNEN8Du4mkQ?e=Ao2uSU")
.build())
.parse().onSuccess(res -> {
System.out.println(res);
});
// }
}
}