AndroidCatVodSpider/app/src/main/java/com/github/catvod/api/YunDrive.java

191 lines
8.1 KiB
Java

package com.github.catvod.api;
import com.github.catvod.net.OkHttp;
import com.github.catvod.net.OkResult;
import com.github.catvod.utils.Json;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class YunDrive {
private final Pattern regex = Pattern.compile("https://yun\\.139\\.com/shareweb/#/w/i/([^&]+)");
private final SecretKeySpec secretKey;
private final String baseUrl = "https://share-kd-njs.yun.139.com/yun-share/richlifeApp/devapp/IOutLink/";
private final Map<String, String> baseHeaders = new HashMap<>();
private final Map<String, JsonObject> cache = new HashMap<>();
private static class Loader {
static volatile YunDrive INSTANCE = new YunDrive();
}
public static YunDrive get() {
return Loader.INSTANCE;
}
public YunDrive() {
this.secretKey = new SecretKeySpec("PVGDwmcvfs1uV3d1".getBytes(Charset.defaultCharset()), "AES");
baseHeaders.put("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");
baseHeaders.put("Content-Type", "application/json");
baseHeaders.put("hcy-cool-flag", "1");
baseHeaders.put("x-deviceinfo", "||3|12.27.0|chrome|131.0.0.0|5c7c68368f048245e1ce47f1c0f8f2d0||windows 10|1536X695|zh-CN|||");
}
private String encrypt(String data) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
byte[] ivBytes = new byte[16];
new SecureRandom().nextBytes(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(ivBytes));
byte[] encrypted = cipher.doFinal(data.getBytes(Charset.defaultCharset()));
byte[] combined = new byte[ivBytes.length + encrypted.length];
System.arraycopy(ivBytes, 0, combined, 0, ivBytes.length);
System.arraycopy(encrypted, 0, combined, ivBytes.length, encrypted.length);
return Base64.encodeBase64String(combined);
}
private String decrypt(String data) throws GeneralSecurityException {
byte[] combined = Base64.decodeBase64(data);
byte[] ivBytes = Arrays.copyOfRange(combined, 0, 16);
byte[] encrypted = Arrays.copyOfRange(combined, 16, combined.length);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(ivBytes));
return new String(cipher.doFinal(encrypted), Charset.defaultCharset());
}
public String extractLinkID(String url) {
String linkID = "";
Matcher matcher = regex.matcher(url);
boolean finded = matcher.find();
if (!finded) {
matcher = Pattern.compile("https://caiyun\\.139\\.com/m/i\\?([^&]+)").matcher(url);
finded = matcher.find();
}
if (finded) linkID = matcher.group(1);
return linkID;
}
public JsonObject fetchShareInfo(String pCaID, String linkID) throws IOException, GeneralSecurityException {
if (linkID.isEmpty()) throw new IllegalStateException("linkID not initialized");
String cacheKey = linkID + "-" + pCaID;
if (cache.containsKey(cacheKey)) return cache.get(cacheKey);
Map<String, Object> requestBody = Map.of("getOutLinkInfoReq", Map.of("account", "", "linkID", linkID, "passwd", "", "caSrt", 1, "coSrt", 1, "srtDr", 0, "bNum", 1, "pCaID", pCaID, "eNum", 200), "commonAccountInfo", Map.of("account", "", "accountType", 1));
OkResult okResult = OkHttp.post(baseUrl + "getOutLinkInfoV6", encrypt(Json.toJson(requestBody)), baseHeaders);
JsonObject result = Json.safeObject(decrypt(okResult.getBody())).getAsJsonObject("data");
cache.put(cacheKey, result);
return result;
}
public Map<String, List<Map<String, String>>> processShareData(String url) throws Exception {
if (url == null || url.isEmpty()) return Collections.emptyMap();
boolean isUrl = url.startsWith("http");
String pCaID = isUrl ? "root" : url;
String linkID = "";
if (isUrl) linkID = extractLinkID(url);
List<Map<String, String>> fileList = fetchFileList(pCaID, linkID);
Map<String, List<Map<String, String>>> result = new LinkedHashMap<>();
for (Map<String, String> item : fileList) {
String name = item.get("name");
List<Map<String, String>> subItems = fetchUrlList(item.get("path"), linkID);
if (!subItems.isEmpty()) {
List<Map<String, String>> list = result.get(name);
if (list == null) {
list = new ArrayList<>();
result.put(name, list);
}
list.addAll(subItems);
}
}
if (result.isEmpty()) {
List<Map<String, String>> rootItems = fetchFileList(url, linkID);
List<Map<String, String>> filteredList = new ArrayList<>();
for (Map<String, String> m : rootItems) {
if (!m.isEmpty()) {
filteredList.add(m);
}
}
result.put("root", filteredList);
}
return result;
}
private List<Map<String, String>> fetchFileList(String pCaID, String linkID) throws Exception {
if (pCaID == null) return Collections.emptyList();
String actualID = pCaID.startsWith("http") ? "root" : pCaID;
JsonObject response = fetchShareInfo(actualID, linkID);
if (!response.has("caLst")) return Collections.emptyList();
List<Map<String, String>> items = new ArrayList<>();
Pattern filter = Pattern.compile("App|活动中心|免费|1T空间|免流");
JsonElement array = response.get("caLst");
if (!array.isJsonNull()) {
for (JsonElement element : array.getAsJsonArray()) {
JsonObject entry = element.getAsJsonObject();
String name = entry.get("caName").getAsString();
String path = entry.get("path").getAsString();
if (!filter.matcher(name).find()) {
items.add(Map.of("name", name, "path", path));
items.addAll(fetchFileList(path, linkID));
}
}
}
return items;
}
private List<Map<String, String>> fetchUrlList(String pCaID, String linkID) throws Exception {
JsonObject response = fetchShareInfo(pCaID, linkID);
List<Map<String, String>> items = new ArrayList<>();
if (response.has("coLst")) {
for (JsonElement element : response.getAsJsonArray("coLst")) {
JsonObject entry = element.getAsJsonObject();
if (entry.get("coType").getAsInt() == 3) {
items.add(Map.of("name", entry.get("coName").getAsString(), "contentId", entry.get("coID").getAsString(), "linkID", linkID));
}
}
} else if (response.has("caLst")) {
for (JsonElement element : response.getAsJsonArray("caLst")) {
items.addAll(fetchUrlList(element.getAsJsonObject().get("path").getAsString(), linkID));
}
}
return items;
}
public String fetchPlayUrl(String contentId, String linkID) throws Exception {
Map<String, Object> requestBody = Map.of("getContentInfoFromOutLinkReq", Map.of("contentId", contentId, "linkID", linkID, "account", ""), "commonAccountInfo", Map.of("account", "", "accountType", 1));
OkResult okResult = OkHttp.post(baseUrl + "getContentInfoFromOutLink", Json.toJson(requestBody), Map.of("Accept-Encoding", "gzip, deflate, br, zstd", "User-Agent", baseHeaders.get("User-Agent")));
return Json.safeObject(okResult.getBody()).getAsJsonObject("data").getAsJsonObject("contentInfo").get("presentURL").getAsString();
}
}