mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2025-12-19 13:53:02 +00:00
修复蓝奏优享解析失败, gz压缩的json解析
This commit is contained in:
@@ -5,7 +5,7 @@ import cn.qaiu.entity.ShareLinkInfo;
|
|||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
import io.vertx.core.Handler;
|
import io.vertx.core.Handler;
|
||||||
import io.vertx.core.Promise;
|
import io.vertx.core.Promise;
|
||||||
import io.vertx.core.json.DecodeException;
|
import io.vertx.core.buffer.Buffer;
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
import io.vertx.core.net.ProxyOptions;
|
import io.vertx.core.net.ProxyOptions;
|
||||||
import io.vertx.core.net.ProxyType;
|
import io.vertx.core.net.ProxyType;
|
||||||
@@ -17,8 +17,14 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析器抽象类包含promise, HTTP Client, 默认失败方法等;
|
* 解析器抽象类包含promise, HTTP Client, 默认失败方法等;
|
||||||
@@ -146,21 +152,56 @@ public abstract class PanBase implements IPanTool {
|
|||||||
return handleFail("");
|
return handleFail("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bodyAsJsonObject的封装, 会自动处理异常
|
* bodyAsJsonObject的封装, 会自动处理异常
|
||||||
|
*
|
||||||
* @param res HttpResponse
|
* @param res HttpResponse
|
||||||
* @return JsonObject
|
* @return JsonObject
|
||||||
*/
|
*/
|
||||||
protected JsonObject asJson(HttpResponse<?> res) {
|
protected JsonObject asJson(HttpResponse<?> res) {
|
||||||
try {
|
try {
|
||||||
return res.bodyAsJsonObject();
|
// 检查响应头中的Content-Encoding是否为gzip
|
||||||
} catch (DecodeException e) {
|
String contentEncoding = res.getHeader("Content-Encoding");
|
||||||
|
if ("gzip".equalsIgnoreCase(contentEncoding)) {
|
||||||
|
// 如果是gzip压缩的响应体,解压
|
||||||
|
return new JsonObject(decompressGzip((Buffer) res.body()));
|
||||||
|
} else {
|
||||||
|
return res.bodyAsJsonObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
fail("解析失败: json格式异常: {}", res.bodyAsString());
|
fail("解析失败: json格式异常: {}", res.bodyAsString());
|
||||||
throw new RuntimeException("解析失败: json格式异常");
|
throw new RuntimeException("解析失败: json格式异常");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解压gzip数据
|
||||||
|
* @param compressedData compressedData
|
||||||
|
* @return String
|
||||||
|
* @throws IOException IOException
|
||||||
|
*/
|
||||||
|
private String decompressGzip(Buffer compressedData) throws IOException {
|
||||||
|
try (ByteArrayInputStream bais = new ByteArrayInputStream(compressedData.getBytes());
|
||||||
|
GZIPInputStream gzis = new GZIPInputStream(bais);
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(gzis,
|
||||||
|
StandardCharsets.UTF_8))) {
|
||||||
|
|
||||||
|
// 用于存储解压后的字符串
|
||||||
|
StringBuilder decompressedData = new StringBuilder();
|
||||||
|
|
||||||
|
// 逐行读取解压后的数据
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
decompressedData.append(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 此时decompressedData.toString()包含了解压后的字符串
|
||||||
|
return decompressedData.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected void complete(String url) {
|
protected void complete(String url) {
|
||||||
promise.complete(url);
|
promise.complete(url);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import java.util.UUID;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class IzTool extends PanBase {
|
public class IzTool extends PanBase {
|
||||||
|
|
||||||
private static final String API_URL_PREFIX = "https://api.ilanzou.com/unproved/";
|
private static final String API_URL_PREFIX = "https://api.ilanzou.com/unproved/";
|
||||||
|
|
||||||
private static final String FIRST_REQUEST_URL = API_URL_PREFIX + "recommend/list?devType=6&devModel=Chrome" +
|
private static final String FIRST_REQUEST_URL = API_URL_PREFIX + "recommend/list?devType=6&devModel=Chrome" +
|
||||||
@@ -24,12 +25,38 @@ public class IzTool extends PanBase {
|
|||||||
"&devType=6&uuid={uuid}×tamp={ts}&auth={auth}&shareId={dataKey}";
|
"&devType=6&uuid={uuid}×tamp={ts}&auth={auth}&shareId={dataKey}";
|
||||||
// downloadId=x&enable=1&devType=6&uuid=x×tamp=x&auth=x&shareId=lGFndCM
|
// downloadId=x&enable=1&devType=6&uuid=x×tamp=x&auth=x&shareId=lGFndCM
|
||||||
|
|
||||||
|
private static final String VIP_REQUEST_URL = API_URL_PREFIX + "/buy/vip/list?devType=6&devModel=Chrome&uuid" +
|
||||||
|
"={uuid}&extra=2×tamp={ts}";
|
||||||
|
private static final MultiMap header;
|
||||||
|
|
||||||
|
static {
|
||||||
|
header = MultiMap.caseInsensitiveMultiMap();
|
||||||
|
header.set("Accept", "application/json, text/plain, */*");
|
||||||
|
header.set("Accept-Encoding", "gzip, deflate, br, zstd");
|
||||||
|
header.set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
|
||||||
|
header.set("Cache-Control", "no-cache");
|
||||||
|
header.set("Connection", "keep-alive");
|
||||||
|
header.set("Content-Length", "0");
|
||||||
|
header.set("DNT", "1");
|
||||||
|
header.set("Host", "api.ilanzou.com");
|
||||||
|
header.set("Origin", "https://www.ilanzou.com/");
|
||||||
|
header.set("Pragma", "no-cache");
|
||||||
|
header.set("Referer", "https://www.ilanzou.com/");
|
||||||
|
header.set("Sec-Fetch-Dest", "empty");
|
||||||
|
header.set("Sec-Fetch-Mode", "cors");
|
||||||
|
header.set("Sec-Fetch-Site", "cross-site");
|
||||||
|
header.set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36");
|
||||||
|
header.set("sec-ch-ua", "\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"");
|
||||||
|
header.set("sec-ch-ua-mobile", "?0");
|
||||||
|
header.set("sec-ch-ua-platform", "\"Windows\"");
|
||||||
|
}
|
||||||
|
|
||||||
public IzTool(ShareLinkInfo shareLinkInfo) {
|
public IzTool(ShareLinkInfo shareLinkInfo) {
|
||||||
super(shareLinkInfo);
|
super(shareLinkInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Future<String> parse() {
|
public Future<String> parse() {
|
||||||
String dataKey = shareLinkInfo.getShareKey();
|
String shareId = shareLinkInfo.getShareKey();
|
||||||
long nowTs = System.currentTimeMillis();
|
long nowTs = System.currentTimeMillis();
|
||||||
String tsEncode = AESUtils.encrypt2HexIz(Long.toString(nowTs));
|
String tsEncode = AESUtils.encrypt2HexIz(Long.toString(nowTs));
|
||||||
String uuid = UUID.randomUUID().toString();
|
String uuid = UUID.randomUUID().toString();
|
||||||
@@ -38,45 +65,54 @@ public class IzTool extends PanBase {
|
|||||||
// String shareId = String.valueOf(AESUtils.idEncryptIz(dataKey));
|
// String shareId = String.valueOf(AESUtils.idEncryptIz(dataKey));
|
||||||
|
|
||||||
// 第一次请求 获取文件信息
|
// 第一次请求 获取文件信息
|
||||||
// POST https://api.feijipan.com/ws/recommend/list?devType=6&devModel=Chrome&extra=2&shareId=146731&type=0&offset=1&limit=60
|
// POST https://api.ilanzou.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", dataKey)
|
client.postAbs(UriTemplate.of(VIP_REQUEST_URL))
|
||||||
.setTemplateParam("uuid", uuid)
|
.setTemplateParam("uuid", uuid)
|
||||||
.setTemplateParam("ts", tsEncode)
|
.setTemplateParam("ts", tsEncode)
|
||||||
.send().onSuccess(res -> {
|
.send().onSuccess(r0 -> { // 忽略res
|
||||||
JsonObject resJson = asJson(res);
|
// 第一次请求 获取文件信息
|
||||||
if (resJson.getInteger("code") != 200) {
|
// POST https://api.feijipan.com/ws/recommend/list?devType=6&devModel=Chrome&extra=2&shareId=146731&type=0&offset=1&limit=60
|
||||||
fail(FIRST_REQUEST_URL + " 返回异常: " + resJson);
|
client.postAbs(UriTemplate.of(FIRST_REQUEST_URL))
|
||||||
return;
|
.putHeaders(header)
|
||||||
}
|
.setTemplateParam("shareId", shareId)
|
||||||
if (resJson.getJsonArray("list").size() == 0) {
|
.setTemplateParam("uuid", uuid)
|
||||||
fail(FIRST_REQUEST_URL + " 解析文件列表为空: " + resJson);
|
.setTemplateParam("ts", tsEncode)
|
||||||
return;
|
.send().onSuccess(res -> {
|
||||||
}
|
JsonObject resJson = asJson(res);
|
||||||
// 文件Id
|
if (resJson.getInteger("code") != 200) {
|
||||||
JsonObject fileInfo = resJson.getJsonArray("list").getJsonObject(0);
|
fail(FIRST_REQUEST_URL + " 返回异常: " + resJson);
|
||||||
String fileId = fileInfo.getString("fileIds");
|
return;
|
||||||
String userId = fileInfo.getString("userId");
|
}
|
||||||
// 其他参数
|
if (resJson.getJsonArray("list").size() == 0) {
|
||||||
// String fidEncode = AESUtils.encrypt2HexIz(fileId + "|");
|
fail(FIRST_REQUEST_URL + " 解析文件列表为空: " + resJson);
|
||||||
String fidEncode = AESUtils.encrypt2HexIz(fileId + "|" + userId);
|
return;
|
||||||
String auth = AESUtils.encrypt2HexIz(fileId + "|" + nowTs);
|
}
|
||||||
// 第二次请求
|
// 文件Id
|
||||||
clientNoRedirects.getAbs(UriTemplate.of(SECOND_REQUEST_URL))
|
JsonObject fileInfo = resJson.getJsonArray("list").getJsonObject(0);
|
||||||
.setTemplateParam("fidEncode", fidEncode)
|
String fileId = fileInfo.getString("fileIds");
|
||||||
.setTemplateParam("uuid", uuid)
|
String userId = fileInfo.getString("userId");
|
||||||
.setTemplateParam("ts", tsEncode)
|
// 其他参数
|
||||||
.setTemplateParam("auth", auth)
|
// String fidEncode = AESUtils.encrypt2HexIz(fileId + "|");
|
||||||
.setTemplateParam("shareId", dataKey).send().onSuccess(res2 -> {
|
String fidEncode = AESUtils.encrypt2HexIz(fileId + "|" + userId);
|
||||||
MultiMap headers = res2.headers();
|
String auth = AESUtils.encrypt2HexIz(fileId + "|" + nowTs);
|
||||||
if (!headers.contains("Location")) {
|
// 第二次请求
|
||||||
fail(SECOND_REQUEST_URL + " 未找到重定向URL: \n" + res.headers());
|
clientNoRedirects.getAbs(UriTemplate.of(SECOND_REQUEST_URL))
|
||||||
return;
|
.setTemplateParam("fidEncode", fidEncode)
|
||||||
}
|
.setTemplateParam("uuid", uuid)
|
||||||
promise.complete(headers.get("Location"));
|
.setTemplateParam("ts", tsEncode)
|
||||||
}).onFailure(handleFail(SECOND_REQUEST_URL));
|
.setTemplateParam("auth", auth)
|
||||||
}).onFailure(handleFail(FIRST_REQUEST_URL));
|
.setTemplateParam("shareId", shareId)
|
||||||
|
.putHeaders(header).send().onSuccess(res2 -> {
|
||||||
|
MultiMap headers = res2.headers();
|
||||||
|
if (!headers.contains("Location")) {
|
||||||
|
fail(SECOND_REQUEST_URL + " 未找到重定向URL: \n" + res.headers());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
promise.complete(headers.get("Location"));
|
||||||
|
}).onFailure(handleFail(SECOND_REQUEST_URL));
|
||||||
|
}).onFailure(handleFail(FIRST_REQUEST_URL));
|
||||||
|
});
|
||||||
return promise.future();
|
return promise.future();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user