夸克部分
This commit is contained in:
parent
7dccb854d6
commit
ec15bcd86d
|
|
@ -1,171 +1,302 @@
|
||||||
/*
|
/*
|
||||||
package com.github.catvod.api;
|
package com.github.catvod.api;
|
||||||
|
|
||||||
import com.github.catvod.bean.quark.ShareData;
|
import com.github.catvod.bean.quark.Item;
|
||||||
import com.github.catvod.spider.Init;
|
import com.github.catvod.net.OkHttp;
|
||||||
import com.github.catvod.utils.Path;
|
import com.github.catvod.net.OkResult;
|
||||||
import com.google.gson.Gson;
|
import com.github.catvod.utils.Json;
|
||||||
import com.google.gson.JsonObject;
|
import com.github.catvod.utils.Util;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.security.MessageDigest;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class QuarkApi {
|
public class QuarkApi {
|
||||||
|
private String apiUrl = "https://drive-pc.quark.cn/1/clouddrive/";
|
||||||
private static final String API_URL = "https://drive-pc.QuarkApi.cn/1/clouddrive/";
|
private String cookie = "";
|
||||||
private String cookie;
|
private String ckey = "";
|
||||||
private String ckey;
|
private Map<String, Map<String, Object>> shareTokenCache = new HashMap<>();
|
||||||
private Map<String, Object> shareTokenCache;
|
|
||||||
private String pr = "pr=ucpro&fr=pc";
|
private String pr = "pr=ucpro&fr=pc";
|
||||||
private List<String> subtitleExts;
|
private List<String> subtitleExts = Arrays.asList(".srt", ".ass", ".scc", ".stl", ".ttml");
|
||||||
private Map<String, String> saveFileIdCaches;
|
private Map<String, String> saveFileIdCaches = new HashMap<>();
|
||||||
private String saveDirId;
|
private String saveDirId = null;
|
||||||
private String saveDirName = "TV";
|
private String saveDirName = "TV";
|
||||||
private boolean isVip = false;
|
private boolean isVip = false;
|
||||||
|
|
||||||
private static class Loader {
|
public void initQuark(String cookie) throws Exception {
|
||||||
static volatile QuarkApi INSTANCE = new QuarkApi();
|
this.ckey = bytesToHex(MessageDigest.getInstance("MD5").digest(cookie.getBytes()));
|
||||||
|
this.cookie = cookie;
|
||||||
|
this.isVip = getVip();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static QuarkApi get() {
|
private Map<String, String> getHeaders() {
|
||||||
return QuarkApi.Loader.INSTANCE;
|
Map<String, String> headers = new HashMap<>();
|
||||||
|
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) quark-cloud-drive/2.5.20 Chrome/100.0.4896.160 Electron/18.3.5.4-b478491100 Safari/537.36 Channel/pckk_other_ch");
|
||||||
|
headers.put("Referer", "https://pan.quark.cn/");
|
||||||
|
headers.put("Content-Type", "application/json");
|
||||||
|
headers.put("Cookie", this.cookie);
|
||||||
|
headers.put("Host", "drive-pc.quark.cn");
|
||||||
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getCache() {
|
private String api(String url, Map<String, String> data, Integer retry, String method) throws Exception {
|
||||||
return Path.tv("quark");
|
|
||||||
}
|
|
||||||
|
|
||||||
private QuarkApi() {
|
|
||||||
Init.checkPermission();
|
|
||||||
this.shareTokenCache = new HashMap<>();
|
|
||||||
this.subtitleExts = List.of(".srt", ".ass", ".scc", ".stl", ".ttml");
|
|
||||||
this.saveFileIdCaches = new HashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRefreshToken(String token) {
|
|
||||||
this.cookie = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static String bytesToHex(byte[] bytes) {
|
int leftRetry = retry != null ? retry : 3;
|
||||||
StringBuilder hexString = new StringBuilder();
|
OkResult okResult;
|
||||||
for (byte b : bytes) {
|
if ("get".equals(method)) {
|
||||||
String hex = Integer.toHexString(0xff & b);
|
okResult = OkHttp.get(this.apiUrl + url, data, getHeaders());
|
||||||
if (hex.length() == 1) {
|
|
||||||
hexString.append("0");
|
|
||||||
}
|
|
||||||
hexString.append(hex);
|
|
||||||
}
|
|
||||||
return hexString.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public JsonObject api(String url, String data, Integer retry, String method) {
|
|
||||||
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShareData getShareData(String url) {
|
|
||||||
String regex = "https:\\/\\/pan\\.quark\\.cn\\/s\\/([^\\|#/]+)";
|
|
||||||
Pattern pattern = Pattern.compile(regex);
|
|
||||||
Matcher matcher = pattern.matcher(url);
|
|
||||||
|
|
||||||
if (matcher.find()) {
|
|
||||||
|
|
||||||
return new ShareData(matcher.group(1), "0");
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean getVip() {
|
|
||||||
JsonObject listData = this.api("member?pr=ucpro&fr=pc&uc_param_str=&fetch_subscribe=true&_ch=home&fetch_identity=true", null, null, "get");
|
|
||||||
return "EXP_SVIP".equals(listData.getAsJsonObject("data").getAsJsonObject("member_type").getAsString());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
List<String> getPlayFormatList() {
|
|
||||||
if (this.isVip) {
|
|
||||||
return List.of("4K", "超清", "高清", "普画");
|
|
||||||
} else {
|
} else {
|
||||||
return List.of("普画");
|
okResult = OkHttp.post(this.apiUrl + url, data, getHeaders());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<String> getPlayFormtQuarkList() {
|
if (okResult.getResp().get("Set-Cookie") != null) {
|
||||||
|
Matcher matcher = Pattern.compile("__puus=([^;]+)").matcher(StringUtils.join(okResult.getResp().get("Set-Cookie"), ";;;"));
|
||||||
|
if (matcher.find()) {
|
||||||
|
Matcher cookieMatcher = Pattern.compile("__puus=([^;]+)").matcher(this.cookie);
|
||||||
|
if (cookieMatcher.find() && !cookieMatcher.group(1).equals(matcher.group(1))) {
|
||||||
|
this.cookie = this.cookie.replaceAll("__puus=[^;]+", "__puus=" + matcher.group(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (okResult.getCode() != 200 && leftRetry > 0) {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
return api(url, data, leftRetry - 1, method);
|
||||||
|
}
|
||||||
|
return okResult.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> getShareData(String url) {
|
||||||
|
Pattern pattern = Pattern.compile("https://pan\\.quark\\.cn/s/([^\\\\|#/]+)");
|
||||||
|
Matcher matcher = pattern.matcher(url);
|
||||||
|
if (matcher.find()) {
|
||||||
|
Map<String, String> shareData = new HashMap<>();
|
||||||
|
shareData.put("shareId", matcher.group(1));
|
||||||
|
shareData.put("folderId", "0");
|
||||||
|
return shareData;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getVip() throws Exception {
|
||||||
|
Map<String, Object> listData = Json.parseSafe(api("member?pr=ucpro&fr=pc&uc_param_str=&fetch_subscribe=true&_ch=home&fetch_identity=true", null, 0, "GET"), Map.class);
|
||||||
|
return "EXP_SVIP".equals(((Map<String, String>) listData.get("data")).get("member_type"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getPlayFormatList() {
|
||||||
if (this.isVip) {
|
if (this.isVip) {
|
||||||
return List.of("4k", "2k", "super", "high", "normal", "low");
|
return Arrays.asList("4K", "超清", "高清", "普画");
|
||||||
}
|
} else {
|
||||||
{
|
return Collections.singletonList("普画");
|
||||||
return List.of("low");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void getShareToken(ShareData shareData) {
|
private List<String> getPlayFormatQuarkList() {
|
||||||
if (null != this.shareTokenCache.get(shareData.getShareId())) {
|
if (this.isVip) {
|
||||||
this.shareTokenCache.put(shareData.getShareId(), null);
|
return Arrays.asList("4k", "2k", "super", "high", "normal", "low");
|
||||||
JsonObject shareToken = this.api("share/sharepage/token?" + this.pr, new Gson().toJson(Map.of("pwd_id", shareData.getFolderId(), "passcode", Objects.isNull(shareData.getSharePwd()) ? "" : shareData.getSharePwd())), null, null);
|
} else {
|
||||||
if (shareToken.getAsJsonObject("data") != null && StringUtils.isNoneBlank(shareToken.getAsJsonObject("data").getAsJsonObject("stoken").getAsString())) {
|
return Collections.singletonList("low");
|
||||||
this.shareTokenCache.put(shareData.getShareId(), shareToken.getAsJsonObject("data"));
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getShareToken(Map<String, String> shareData) throws Exception {
|
||||||
|
if (!this.shareTokenCache.containsKey(shareData.get("shareId"))) {
|
||||||
|
this.shareTokenCache.remove(shareData.get("shareId"));
|
||||||
|
Map<String, Object> shareToken = Json.parseSafe(api("share/sharepage/token?" + this.pr, Map.of("pwd_id", shareData.get("shareId"), "passcode", shareData.get("sharePwd")), 0, "POST"), Map.class);
|
||||||
|
if (shareToken.containsKey("data") && ((Map<String, Object>) shareToken.get("data")).containsKey("stoken")) {
|
||||||
|
this.shareTokenCache.put(shareData.get("shareId"), (Map<String, Object>) shareToken.get("data"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Map<String, Object>> listFile(int shareIndex, Map<String, String> shareData, List<Item> videos, List<Item> subtitles, String shareId, String folderId, Integer page) throws Exception {
|
||||||
listFile(shareIndex, shareData, videos, subtitles, shareId, folderId, page) {
|
int prePage = 200;
|
||||||
const prePage = 200;
|
page = page != null ? page : 1;
|
||||||
page = page || 1;
|
Map<String, Object> listData = Json.parseSafe(api("share/sharepage/detail?" + this.pr + "&pwd_id=" + shareId + "&stoken=" + encodeURIComponent((String) this.shareTokenCache.get(shareId).get("stoken")) + "&pdir_fid=" + folderId + "&force=0&_page=" + page + "&_size=" + prePage + "&_sort=file_type:asc,file_name:asc", null, 0, "GET"), Map.class);
|
||||||
const listData = await this.api(
|
if (listData.get("data") == null) return Collections.emptyList();
|
||||||
`share/sharepage/detail?${this.pr}&pwd_id=${shareId}&stoken=${encodeURIComponent(this.shareTokenCache[shareId].stoken)}&pdir_fid=${folderId}&force=0&_page=${page}&_size=${prePage}&_sort=file_type:asc,file_name:asc`,
|
List<Map<String, Object>> items = (List<Map<String, Object>>) ((Map<String, Object>) listData.get("data")).get("list");
|
||||||
null,
|
if (items == null) return Collections.emptyList();
|
||||||
null,
|
List<Map<String, Object>> subDir = new ArrayList<>();
|
||||||
'get',
|
for (Map<String, Object> item : items) {
|
||||||
);
|
if (Boolean.TRUE.equals(item.get("dir"))) {
|
||||||
if (!listData.data) return [];
|
subDir.add(item);
|
||||||
const items = listData.data.list;
|
} else if (Boolean.TRUE.equals(item.get("file")) && "video".equals(item.get("obj_category"))) {
|
||||||
if (!items) return [];
|
if ((int) item.get("size") < 1024 * 1024 * 5) continue;
|
||||||
const subDir = [];
|
item.put("stoken", this.shareTokenCache.get(shareData.get("shareId")).get("stoken"));
|
||||||
for (const item of items) {
|
videos.add(Item.objectFrom(Json.toJson(item), shareData.get("shareId"), shareIndex));
|
||||||
if (item.dir === true) {
|
} else if ("file".equals(item.get("type")) && this.subtitleExts.contains("." + Util.getExt((String) item.get("file_name")))) {
|
||||||
subDir.push(item);
|
subtitles.add(Item.objectFrom(Json.toJson(item), shareData.get("shareId"), shareIndex));
|
||||||
} else if (item.file === true && item.obj_category === 'video') {
|
|
||||||
if (item.size < 1024 * 1024 * 5) continue;
|
|
||||||
item.stoken = this.shareTokenCache[shareData.shareId].stoken;
|
|
||||||
videos.push(Item.objectFrom(item, shareData.shareId, shareIndex));
|
|
||||||
} else if (item.type === 'file' && this.subtitleExts.some((x) => item.file_name.endsWith(x))) {
|
|
||||||
subtitles.push(Item.objectFrom(item, shareData, shareIndex));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (page < Math.ceil(listData.metadata._total / prePage)) {
|
if (page < Math.ceil((double) ((Map<String, Object>) listData.get("metadata")).get("_total") / prePage)) {
|
||||||
const nextItems = await this.listFile(
|
List<Map<String, Object>> nextItems = listFile(shareIndex, shareData, videos, subtitles, shareId, folderId, page + 1);
|
||||||
shareIndex,
|
items.addAll(nextItems);
|
||||||
shareData.shareId,
|
|
||||||
videos,
|
|
||||||
subtitles,
|
|
||||||
shareId,
|
|
||||||
folderId,
|
|
||||||
page + 1,
|
|
||||||
);
|
|
||||||
for (const item of nextItems) {
|
|
||||||
items.push(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const dir of subDir) {
|
|
||||||
const subItems = await this.listFile(shareIndex, shareData, videos, subtitles, shareId, dir.fid);
|
|
||||||
for (const item of subItems) {
|
|
||||||
items.push(item);
|
|
||||||
}
|
}
|
||||||
|
for (Map<String, Object> dir : subDir) {
|
||||||
|
List<Map<String, Object>> subItems = listFile(shareIndex, shareData, videos, subtitles, shareId, dir.get("fid").toString(), null);
|
||||||
|
items.addAll(subItems);
|
||||||
}
|
}
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private Map<String, Object> findBestLCS(Item mainItem, List<Item> targetItems) {
|
||||||
|
List<Map<String, Object>> results = new ArrayList<>();
|
||||||
|
int bestMatchIndex = 0;
|
||||||
|
for (int i = 0; i < targetItems.size(); i++) {
|
||||||
|
Util.LCSResult currentLCS = Util.lcs(mainItem.getName(), targetItems.get(i).getName());
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
result.put("target", targetItems.get(i));
|
||||||
|
result.put("lcs", currentLCS);
|
||||||
|
results.add(result);
|
||||||
|
if (currentLCS.length > results.get(bestMatchIndex).get("lcs").toString().length()) {
|
||||||
|
bestMatchIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Map<String, Object> bestMatch = results.get(bestMatchIndex);
|
||||||
|
Map<String, Object> finalResult = new HashMap<>();
|
||||||
|
finalResult.put("allLCS", results);
|
||||||
|
finalResult.put("bestMatch", bestMatch);
|
||||||
|
finalResult.put("bestMatchIndex", bestMatchIndex);
|
||||||
|
return finalResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getFilesByShareUrl(int shareIndex, Object shareInfo, List<Item> videos, List<Item> subtitles) throws Exception {
|
||||||
|
Map<String, String> shareData = shareInfo instanceof String ? getShareData((String) shareInfo) : (Map<String, String>) shareInfo;
|
||||||
|
if (shareData == null) return;
|
||||||
|
getShareToken(shareData);
|
||||||
|
if (!this.shareTokenCache.containsKey(shareData.get("shareId"))) return;
|
||||||
|
listFile(shareIndex, shareData, videos, subtitles, shareData.get("shareId"), shareData.get("folderId"), 1);
|
||||||
|
if (!subtitles.isEmpty()) {
|
||||||
|
for (Item video : videos) {
|
||||||
|
Map<String, Object> matchSubtitle = findBestLCS(video, subtitles);
|
||||||
|
if (matchSubtitle.get("bestMatch") != null) {
|
||||||
|
video.setSubtitle((String) ((Map<String, Object>) matchSubtitle.get("bestMatch")).get("target"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clean() {
|
||||||
|
saveFileIdCaches.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearSaveDir() throws Exception {
|
||||||
|
Map<String, Object> listData = Json.parseSafe(api("file/sort?" + this.pr + "&pdir_fid=" + this.saveDirId + "&_page=1&_size=200&_sort=file_type:asc,updated_at:desc", Collections.emptyMap(), 0, "GET"), Map.class);
|
||||||
|
if (listData.get("data") != null && ((List<Map<String, Object>>) ((Map<String, Object>) listData.get("data")).get("list")).size() > 0) {
|
||||||
|
api("file/delete?" + this.pr, Map.of("action_type", 2, "filelist", ((List<Map<String, Object>>) ((Map<String, Object>) listData.get("data")).get("list")).stream().map(v -> v.get("fid")).toArray(), "exclude_fids", new Object[]{}), 0, "POST");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createSaveDir(boolean clean) throws Exception {
|
||||||
|
if (this.saveDirId != null) {
|
||||||
|
if (clean) clearSaveDir();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Map<String, Object> listData = Json.parseSafe(api("file/sort?" + this.pr + "&pdir_fid=0&_page=1&_size=200&_sort=file_type:asc,updated_at:desc", Collections.emptyMap(), 0, "GET"), Map.class);
|
||||||
|
if (listData.get("data") != null) {
|
||||||
|
for (Map<String, Object> item : (List<Map<String, Object>>) ((Map<String, Object>) listData.get("data")).get("list")) {
|
||||||
|
if (this.saveDirName.equals(item.get("file_name"))) {
|
||||||
|
this.saveDirId = item.get("fid").toString();
|
||||||
|
clearSaveDir();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.saveDirId == null) {
|
||||||
|
Map<String, Object> create = Json.parseSafe(api("file?" + this.pr, Map.of("pdir_fid", "0", "file_name", this.saveDirName, "dir_path", "", "dir_init_lock", false), 0, "POST"), Map.class);
|
||||||
|
if (create.get("data") != null && ((Map<String, Object>) create.get("data")).get("fid") != null) {
|
||||||
|
this.saveDirId = ((Map<String, Object>) create.get("data")).get("fid").toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String save(String shareId, String stoken, String fileId, String fileToken, boolean clean) throws Exception {
|
||||||
|
createSaveDir(clean);
|
||||||
|
if (clean) {
|
||||||
|
clean();
|
||||||
|
}
|
||||||
|
if (this.saveDirId == null) return null;
|
||||||
|
if (stoken == null) {
|
||||||
|
getShareToken(Map.of("shareId", shareId));
|
||||||
|
if (!this.shareTokenCache.containsKey(shareId)) return null;
|
||||||
|
}
|
||||||
|
Map<String, Object> saveResult = Json.parseSafe(api("share/sharepage/save?" + this.pr, Map.of("fid_list", new String[]{fileId}, "fid_token_list", new String[]{fileToken}, "to_pdir_fid", this.saveDirId, "pwd_id", shareId, "stoken", stoken != null ? stoken : this.shareTokenCache.get(shareId).get("stoken"), "pdir_fid", "0", "scene", "link"), 0, "POST"), Map.class);
|
||||||
|
if (saveResult.get("data") != null && ((Map<String, Object>) saveResult.get("data")).get("task_id") != null) {
|
||||||
|
int retry = 0;
|
||||||
|
while (true) {
|
||||||
|
Map<String, Object> taskResult = Json.parseSafe(api("task?" + this.pr + "&task_id=" + ((Map<String, Object>) saveResult.get("data")).get("task_id") + "&retry_index=" + retry, Collections.emptyMap(), 0, "GET"), Map.class);
|
||||||
|
if (taskResult.get("data") != null && ((Map<String, Object>) taskResult.get("data")).get("save_as") != null && ((Map<String, Object>) ((Map<String, Object>) taskResult.get("data")).get("save_as")).get("save_as_top_fids") != null && ((List<String>) ((Map<String, Object>) ((Map<String, Object>) taskResult.get("data")).get("save_as")).get("save_as_top_fids")).size() > 0) {
|
||||||
|
return ((List<String>) ((Map<String, Object>) ((Map<String, Object>) taskResult.get("data")).get("save_as")).get("save_as_top_fids")).get(0);
|
||||||
|
}
|
||||||
|
retry++;
|
||||||
|
if (retry > 2) break;
|
||||||
|
Thread.sleep(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getLiveTranscoding(String shareId, String stoken, String fileId, String fileToken, String flag) throws Exception {
|
||||||
|
if (!this.saveFileIdCaches.containsKey(fileId)) {
|
||||||
|
String saveFileId = save(shareId, stoken, fileId, fileToken, true);
|
||||||
|
if (saveFileId == null) return null;
|
||||||
|
this.saveFileIdCaches.put(fileId, saveFileId);
|
||||||
|
}
|
||||||
|
Map<String, Object> transcoding = Json.parseSafe(api("file/v2/play?" + this.pr, Map.of("fid", this.saveFileIdCaches.get(fileId), "resolutions", "normal,low,high,super,2k,4k", "supports", "fmp4"), 0, "POST"), Map.class);
|
||||||
|
if (transcoding.get("data") != null && ((Map<String, Object>) transcoding.get("data")).get("video_list") != null) {
|
||||||
|
String flagId = flag.split("-")[flag.split("-").length - 1];
|
||||||
|
int index = Utils.findAllIndexes(getPlayFormatList(), flagId);
|
||||||
|
String quarkFormat = getPlayFormatQuarkList().get(index);
|
||||||
|
for (Map<String, Object> video : (List<Map<String, Object>>) ((Map<String, Object>) transcoding.get("data")).get("video_list")) {
|
||||||
|
if (video.get("resolution").equals(quarkFormat)) {
|
||||||
|
return video.get("video_info").toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ((List<Map<String, Object>>) ((Map<String, Object>) transcoding.get("data")).get("video_list")).get(index).get("video_info").toString();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDownload(String shareId, String stoken, String fileId, String fileToken, boolean clean) throws Exception {
|
||||||
|
if (!this.saveFileIdCaches.containsKey(fileId)) {
|
||||||
|
String saveFileId = save(shareId, stoken, fileId, fileToken, clean);
|
||||||
|
if (saveFileId == null) return null;
|
||||||
|
this.saveFileIdCaches.put(fileId, saveFileId);
|
||||||
|
}
|
||||||
|
Map<String, Object> down = Json.parseSafe(api("file/download?" + this.pr + "&uc_param_str=", Map.of("fids", this.saveFileIdCaches.get(fileId)), 0, "POST"), Map.class);
|
||||||
|
if (down.get("data") != null) {
|
||||||
|
return ((List<String>) down.get("data")).get(0);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method to convert bytes to hex string
|
||||||
|
private String bytesToHex(byte[] bytes) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (byte b : bytes) {
|
||||||
|
sb.append(String.format("%02x", b));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encoding helper method
|
||||||
|
private String encodeURIComponent(String value) {
|
||||||
|
try {
|
||||||
|
return java.net.URLEncoder.encode(value, "UTF-8");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
*/
|
}*/
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ public class Item {
|
||||||
private String shareData;
|
private String shareData;
|
||||||
private int shareIndex;
|
private int shareIndex;
|
||||||
private long lastUpdateAt;
|
private long lastUpdateAt;
|
||||||
|
private String subtitle;
|
||||||
|
|
||||||
public Item() {
|
public Item() {
|
||||||
this.fileId = "";
|
this.fileId = "";
|
||||||
|
|
@ -55,6 +56,14 @@ public class Item {
|
||||||
return arr[arr.length - 1];
|
return arr[arr.length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSubtitle() {
|
||||||
|
return subtitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSubtitle(String subtitle) {
|
||||||
|
this.subtitle = subtitle;
|
||||||
|
}
|
||||||
|
|
||||||
public String getFileId() {
|
public String getFileId() {
|
||||||
return fileId.isEmpty() ? "" : fileId;
|
return fileId.isEmpty() ? "" : fileId;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ public class OkHttp {
|
||||||
|
|
||||||
private OkHttpClient client;
|
private OkHttpClient client;
|
||||||
|
|
||||||
|
|
||||||
private static class Loader {
|
private static class Loader {
|
||||||
static volatile OkHttp INSTANCE = new OkHttp();
|
static volatile OkHttp INSTANCE = new OkHttp();
|
||||||
}
|
}
|
||||||
|
|
@ -53,6 +54,10 @@ public class OkHttp {
|
||||||
return url.startsWith("http") ? new OkRequest(GET, url, params, header).execute(client()).getBody() : "";
|
return url.startsWith("http") ? new OkRequest(GET, url, params, header).execute(client()).getBody() : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static OkResult get(String url, Map<String, String> params, Map<String, String> header) {
|
||||||
|
return new OkRequest(GET, url, params, header).execute(client());
|
||||||
|
}
|
||||||
|
|
||||||
public static String post(String url, Map<String, String> params) {
|
public static String post(String url, Map<String, String> params) {
|
||||||
return post(url, params, null).getBody();
|
return post(url, params, null).getBody();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,10 @@ public class Json {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String toJson(Object obj) {
|
||||||
|
return new Gson().toJson(obj);
|
||||||
|
}
|
||||||
|
|
||||||
public static <T> T parseSafe(String json, Type t) {
|
public static <T> T parseSafe(String json, Type t) {
|
||||||
try {
|
try {
|
||||||
return new Gson().fromJson(json, t);
|
return new Gson().fromJson(json, t);
|
||||||
|
|
|
||||||
|
|
@ -274,4 +274,65 @@ public class Util {
|
||||||
public static String base64Decode(String s) {
|
public static String base64Decode(String s) {
|
||||||
return new String(android.util.Base64.decode(s, Base64.DEFAULT), Charset.defaultCharset());
|
return new String(android.util.Base64.decode(s, Base64.DEFAULT), Charset.defaultCharset());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符串相似度匹配
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static LCSResult lcs(String str1, String str2) {
|
||||||
|
if (str1 == null || str2 == null) {
|
||||||
|
return new LCSResult(0, "", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder sequence = new StringBuilder();
|
||||||
|
int str1Length = str1.length();
|
||||||
|
int str2Length = str2.length();
|
||||||
|
int[][] num = new int[str1Length][str2Length];
|
||||||
|
int maxlen = 0;
|
||||||
|
int lastSubsBegin = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < str1Length; i++) {
|
||||||
|
for (int j = 0; j < str2Length; j++) {
|
||||||
|
if (str1.charAt(i) != str2.charAt(j)) {
|
||||||
|
num[i][j] = 0;
|
||||||
|
} else {
|
||||||
|
if (i == 0 || j == 0) {
|
||||||
|
num[i][j] = 1;
|
||||||
|
} else {
|
||||||
|
num[i][j] = 1 + num[i - 1][j - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num[i][j] > maxlen) {
|
||||||
|
maxlen = num[i][j];
|
||||||
|
int thisSubsBegin = i - num[i][j] + 1;
|
||||||
|
if (lastSubsBegin == thisSubsBegin) {
|
||||||
|
// if the current LCS is the same as the last time this block ran
|
||||||
|
sequence.append(str1.charAt(i));
|
||||||
|
} else {
|
||||||
|
// this block resets the string builder if a different LCS is found
|
||||||
|
lastSubsBegin = thisSubsBegin;
|
||||||
|
sequence.setLength(0); // clear it
|
||||||
|
sequence.append(str1.substring(lastSubsBegin, i + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new LCSResult(maxlen, sequence.toString(), lastSubsBegin);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LCSResult {
|
||||||
|
public int length;
|
||||||
|
public String sequence;
|
||||||
|
public int offset;
|
||||||
|
|
||||||
|
public LCSResult(int length, String sequence, int offset) {
|
||||||
|
this.length = length;
|
||||||
|
this.sequence = sequence;
|
||||||
|
this.offset = offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue