mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2025-12-17 12:53:02 +00:00
添加蓝奏云优享解析支持
This commit is contained in:
@@ -19,6 +19,7 @@ public interface IPanTool {
|
||||
case "le" -> new LeTool(key, pwd);
|
||||
case "ws" -> new WsTool(key, pwd);
|
||||
case "qq" -> new QQTool(key, pwd);
|
||||
case "iz" -> new IzTool(key, pwd);
|
||||
default -> {
|
||||
throw new UnsupportedOperationException("未知分享类型");
|
||||
}
|
||||
@@ -39,6 +40,8 @@ public interface IPanTool {
|
||||
return new YeTool(url, pwd);
|
||||
} else if (url.startsWith(FjTool.SHARE_URL_PREFIX) || url.startsWith(FjTool.SHARE_URL_PREFIX2)) {
|
||||
return new FjTool(url, pwd);
|
||||
} else if (url.startsWith(IzTool.SHARE_URL_PREFIX)) {
|
||||
return new IzTool(url, pwd);
|
||||
} else if (url.contains(LzTool.LINK_KEY)) {
|
||||
return new LzTool(url, pwd);
|
||||
} else if (url.startsWith(LeTool.SHARE_URL_PREFIX)) {
|
||||
|
||||
78
parser/src/main/java/cn/qaiu/parser/impl/IzTool.java
Normal file
78
parser/src/main/java/cn/qaiu/parser/impl/IzTool.java
Normal file
@@ -0,0 +1,78 @@
|
||||
package cn.qaiu.parser.impl;
|
||||
|
||||
import cn.qaiu.parser.IPanTool;
|
||||
import cn.qaiu.parser.PanBase;
|
||||
import cn.qaiu.util.AESUtils;
|
||||
import cn.qaiu.util.CommonUtils;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.MultiMap;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.client.WebClient;
|
||||
import io.vertx.uritemplate.UriTemplate;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 小飞机网盘
|
||||
*
|
||||
* @version V016_230609
|
||||
*/
|
||||
public class IzTool extends PanBase implements IPanTool {
|
||||
|
||||
public static final String SHARE_URL_PREFIX = "https://www.ilanzou.com/s/";
|
||||
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&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 IzTool(String key, String pwd) {
|
||||
super(key, pwd);
|
||||
}
|
||||
|
||||
public Future<String> parse() {
|
||||
String dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, key);
|
||||
|
||||
WebClient client = clientNoRedirects;
|
||||
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
|
||||
client.postAbs(UriTemplate.of(FIRST_REQUEST_URL)).setTemplateParam("shareId", shareId).send().onSuccess(res -> {
|
||||
JsonObject resJson = res.bodyAsJsonObject();
|
||||
if (resJson.getInteger("code") != 200) {
|
||||
fail(FIRST_REQUEST_URL + " 返回异常: " + resJson);
|
||||
return;
|
||||
}
|
||||
if (resJson.getJsonArray("list").size() == 0) {
|
||||
fail(FIRST_REQUEST_URL + " 解析文件列表为空: " + resJson);
|
||||
return;
|
||||
}
|
||||
// 文件Id
|
||||
String fileId = resJson.getJsonArray("list").getJsonObject(0).getString("fileIds");
|
||||
// 其他参数
|
||||
long nowTs = System.currentTimeMillis();
|
||||
String tsEncode = AESUtils.encrypt2HexIz(Long.toString(nowTs));
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
String fidEncode = AESUtils.encrypt2HexIz(fileId + "|");
|
||||
String auth = AESUtils.encrypt2HexIz(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")) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,10 @@ public class AESUtils {
|
||||
|
||||
public static final String CIPHER_AES2 = "YbQHZqK/PdQql2+7ATcPQHREAxt0Hn0Ob9v317QirZM=";
|
||||
|
||||
public static final String CIPHER_AES2_IZ = "1uQFS3sNeHd/bCrmrQpflXREAxt0Hn0Ob9v317QirZM=";
|
||||
|
||||
public static final String CIPHER_AES0;
|
||||
public static final String CIPHER_AES0_IZ;
|
||||
|
||||
/**
|
||||
* 秘钥长度
|
||||
@@ -59,6 +62,7 @@ public class AESUtils {
|
||||
static {
|
||||
try {
|
||||
CIPHER_AES0 = decryptByBase64AES(CIPHER_AES2, CIPHER_AES);
|
||||
CIPHER_AES0_IZ = decryptByBase64AES(CIPHER_AES2_IZ, CIPHER_AES);
|
||||
} catch (IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException | NoSuchAlgorithmException |
|
||||
InvalidKeyException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -154,6 +158,15 @@ public class AESUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static String encrypt2HexIz(String source) {
|
||||
try {
|
||||
return encryptHexByAES(source, CIPHER_AES0_IZ);
|
||||
} catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | IllegalBlockSizeException |
|
||||
BadPaddingException e) {
|
||||
throw new RuntimeException("加密失败: "+ e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AES解密
|
||||
*
|
||||
@@ -214,10 +227,14 @@ public class AESUtils {
|
||||
'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'L', 'R', 'S', 'I',
|
||||
'J', 'K'};
|
||||
|
||||
private static int decodeChar(char c) {
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (c == array[i]) {
|
||||
private static final char[] arrayIz =
|
||||
{'Y', 'y', '0', 'Z', 'z', 'N', 'n', 'M', 'I', '6', 'm', 'W', 'w', '1', 'X', 'x', 'L', 'l', 'K', '7', 'k',
|
||||
'i', 'U', 'u', '2', 'V', 'v', 'J', 'j', '8', 'G', 'g', 'F', 'S', 's', '3', 'T', 't', 'H', 'h',
|
||||
'f', 'E', 'e', 'D', 'Q', 'q', '4', 'R', 'r', '9', 'd', 'a', 'C', 'c', 'B', 'O', 'o', '5', 'P',
|
||||
'p', 'b', 'A'};
|
||||
private static int decodeChar(char c, char[] keys) {
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
if (c == keys[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -226,21 +243,46 @@ public class AESUtils {
|
||||
|
||||
// id解密
|
||||
public static int idEncrypt(String str) {
|
||||
return idEncrypt0(str, array, 2, 2);
|
||||
}
|
||||
|
||||
// ================================蓝奏优享版Id解密========================================== //
|
||||
public static int idEncryptIz(String str) {
|
||||
// idEncrypt(e) {
|
||||
// let t = 1
|
||||
// , n = 0;
|
||||
// if ("" != e && e.length > 4) {
|
||||
// let r;
|
||||
// e = e.substring(3, e.length - 1);
|
||||
// for (let v = 0; v < e.length; v++)
|
||||
// r = e.charAt(e.length - v - 1),
|
||||
// n += this.decodeChar(r) * t,
|
||||
// t *= 62
|
||||
// }
|
||||
// return n
|
||||
// },
|
||||
|
||||
return idEncrypt0(str, arrayIz, 3, 1);
|
||||
}
|
||||
|
||||
public static int idEncrypt0(String str, char[] keys, int x1, int x2) {
|
||||
// 倍数
|
||||
int multiple = 1;
|
||||
int result = 0;
|
||||
if (StringUtils.isNotEmpty(str) && str.length() > 4) {
|
||||
str = str.substring(2, str.length() - 2);
|
||||
str = str.substring(x1, str.length() - x2);
|
||||
char c;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
c = str.charAt(str.length() - i - 1);
|
||||
result += decodeChar(c) * multiple;
|
||||
result += decodeChar(c, keys) * multiple;
|
||||
multiple = multiple * 62;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ========================== musetransfer加密相关 ===========================
|
||||
|
||||
//length用户要求产生字符串的长度
|
||||
|
||||
@@ -50,6 +50,12 @@ public class TestAESUtil {
|
||||
Assert.assertEquals(146731, AESUtils.idEncrypt("7jy0zlv"));
|
||||
}
|
||||
|
||||
// 蓝奏优享
|
||||
@Test
|
||||
public void testIzIdDecode() {
|
||||
Assert.assertEquals(26216, AESUtils.idEncryptIz("lGFndCM"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test00() throws IllegalBlockSizeException, NoSuchPaddingException, BadPaddingException,
|
||||
NoSuchAlgorithmException, InvalidKeyException {
|
||||
|
||||
Reference in New Issue
Block a user