mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2026-06-12 00:17:29 +00:00
feat(v0.2.1): 添加认证参数支持和客户端下载命令生成
主要更新: - 新增 auth 参数加密传递支持 (QK/UC Cookie认证) - 实现下载命令自动生成 (curl/aria2c/迅雷) - aria2c 命令支持 8 线程 8 片段下载 - 修复 cookie 字段映射问题 - 优化前端 clientLinks 页面 - 添加认证参数文档和测试用例 - 更新 .gitignore 忽略编译目录
This commit is contained in:
209
parser/src/test/java/cn/qaiu/parser/auth/AuthParamTest.java
Normal file
209
parser/src/test/java/cn/qaiu/parser/auth/AuthParamTest.java
Normal file
@@ -0,0 +1,209 @@
|
||||
package cn.qaiu.parser.auth;
|
||||
|
||||
import cn.qaiu.util.CookieUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Cookie 工具测试
|
||||
*/
|
||||
public class AuthParamTest {
|
||||
|
||||
@Test
|
||||
public void testCookieFilter() {
|
||||
System.out.println("\n=== 测试 Cookie 过滤功能 ===");
|
||||
// 测试 Cookie 过滤功能
|
||||
String fullCookie = "__pus=abc123; __kp=def456; other_cookie=xyz; __puus=token789; random=test; __uid=user001";
|
||||
String filtered = CookieUtils.filterUcQuarkCookie(fullCookie);
|
||||
|
||||
System.out.println("原始 Cookie: " + fullCookie);
|
||||
System.out.println("过滤后 Cookie: " + filtered);
|
||||
|
||||
// 验证包含必要字段
|
||||
assertTrue("应包含 __pus", filtered.contains("__pus=abc123"));
|
||||
assertTrue("应包含 __kp", filtered.contains("__kp=def456"));
|
||||
assertTrue("应包含 __puus", filtered.contains("__puus=token789"));
|
||||
assertTrue("应包含 __uid", filtered.contains("__uid=user001"));
|
||||
|
||||
// 验证不包含不必要字段
|
||||
assertFalse("不应包含 other_cookie", filtered.contains("other_cookie"));
|
||||
assertFalse("不应包含 random", filtered.contains("random"));
|
||||
|
||||
System.out.println("✓ Cookie 过滤测试通过");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCookieGetValue() {
|
||||
System.out.println("\n=== 测试获取 Cookie 值 ===");
|
||||
String cookie = "__pus=value1; __kp=value2; __puus=value3";
|
||||
|
||||
String pus = CookieUtils.getCookieValue(cookie, "__pus");
|
||||
String kp = CookieUtils.getCookieValue(cookie, "__kp");
|
||||
String puus = CookieUtils.getCookieValue(cookie, "__puus");
|
||||
String notexist = CookieUtils.getCookieValue(cookie, "notexist");
|
||||
|
||||
System.out.println("Cookie: " + cookie);
|
||||
System.out.println("__pus = " + pus);
|
||||
System.out.println("__kp = " + kp);
|
||||
System.out.println("__puus = " + puus);
|
||||
System.out.println("notexist = " + notexist);
|
||||
|
||||
assertEquals("value1", pus);
|
||||
assertEquals("value2", kp);
|
||||
assertEquals("value3", puus);
|
||||
assertNull(notexist);
|
||||
|
||||
System.out.println("✓ 获取 Cookie 值测试通过");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCookieUpdate() {
|
||||
System.out.println("\n=== 测试更新 Cookie ===");
|
||||
String cookie = "__pus=old_pus; __kp=value2";
|
||||
String updated = CookieUtils.updateCookieValue(cookie, "__puus", "__puus=new_puus_value");
|
||||
|
||||
System.out.println("更新前: " + cookie);
|
||||
System.out.println("更新后: " + updated);
|
||||
|
||||
assertTrue("应包含新的 __puus", updated.contains("__puus=new_puus_value"));
|
||||
assertTrue("应保留 __pus", updated.contains("__pus=old_pus"));
|
||||
assertTrue("应保留 __kp", updated.contains("__kp=value2"));
|
||||
|
||||
// 测试替换已存在的值
|
||||
String cookie2 = "__pus=old_value; __kp=value2; __puus=old_puus";
|
||||
String updated2 = CookieUtils.updateCookieValue(cookie2, "__puus", "__puus=updated_puus");
|
||||
|
||||
System.out.println("替换测试 - 更新前: " + cookie2);
|
||||
System.out.println("替换测试 - 更新后: " + updated2);
|
||||
|
||||
assertTrue("应包含更新的 __puus", updated2.contains("__puus=updated_puus"));
|
||||
assertFalse("不应包含旧的 __puus", updated2.contains("__puus=old_puus"));
|
||||
|
||||
System.out.println("✓ 更新 Cookie 测试通过");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCookieContainsKey() {
|
||||
System.out.println("\n=== 测试检查 Cookie key 存在性 ===");
|
||||
String cookie = "__pus=value1; __kp=value2; __uid=user123";
|
||||
|
||||
boolean hasPus = CookieUtils.containsKey(cookie, "__pus");
|
||||
boolean hasKp = CookieUtils.containsKey(cookie, "__kp");
|
||||
boolean hasPuus = CookieUtils.containsKey(cookie, "__puus");
|
||||
boolean hasNotexist = CookieUtils.containsKey(cookie, "notexist");
|
||||
|
||||
System.out.println("Cookie: " + cookie);
|
||||
System.out.println("containsKey(__pus): " + hasPus);
|
||||
System.out.println("containsKey(__kp): " + hasKp);
|
||||
System.out.println("containsKey(__puus): " + hasPuus);
|
||||
System.out.println("containsKey(notexist): " + hasNotexist);
|
||||
|
||||
assertTrue(hasPus);
|
||||
assertTrue(hasKp);
|
||||
assertFalse(hasPuus);
|
||||
assertFalse(hasNotexist);
|
||||
|
||||
System.out.println("✓ 检查 Cookie key 测试通过");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyCookieHandling() {
|
||||
System.out.println("\n=== 测试空 Cookie 处理 ===");
|
||||
// 测试空 Cookie 处理
|
||||
String emptyFiltered = CookieUtils.filterUcQuarkCookie("");
|
||||
String nullFiltered = CookieUtils.filterUcQuarkCookie(null);
|
||||
String emptyValue = CookieUtils.getCookieValue("", "__pus");
|
||||
String nullValue = CookieUtils.getCookieValue(null, "__pus");
|
||||
|
||||
System.out.println("filterUcQuarkCookie(''): '" + emptyFiltered + "'");
|
||||
System.out.println("filterUcQuarkCookie(null): '" + nullFiltered + "'");
|
||||
System.out.println("getCookieValue('', '__pus'): " + emptyValue);
|
||||
System.out.println("getCookieValue(null, '__pus'): " + nullValue);
|
||||
|
||||
assertEquals("", emptyFiltered);
|
||||
assertEquals("", nullFiltered);
|
||||
assertNull(emptyValue);
|
||||
assertNull(nullValue);
|
||||
|
||||
System.out.println("✓ 空 Cookie 处理测试通过");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComplexCookieScenario() {
|
||||
System.out.println("\n=== 测试复杂场景:模拟 UC/夸克 Cookie 处理流程 ===");
|
||||
|
||||
// 模拟从浏览器获取的完整 Cookie
|
||||
String browserCookie = "session_id=xxx; __pus=main_token_here; other=value; " +
|
||||
"__kp=key123; __kps=secret456; __ktd=token789; " +
|
||||
"__uid=user001; random_cookie=test; __puus=old_signature";
|
||||
|
||||
System.out.println("1. 浏览器原始 Cookie:");
|
||||
System.out.println(" " + browserCookie);
|
||||
|
||||
// 第一步:过滤出必要的字段
|
||||
String filtered = CookieUtils.filterUcQuarkCookie(browserCookie);
|
||||
System.out.println("\n2. 过滤后的 Cookie (只保留 UC/夸克必需字段):");
|
||||
System.out.println(" " + filtered);
|
||||
|
||||
// 验证过滤结果
|
||||
assertTrue("应包含 __pus", filtered.contains("__pus=main_token_here"));
|
||||
assertTrue("应包含 __kp", filtered.contains("__kp=key123"));
|
||||
assertTrue("应包含 __puus", filtered.contains("__puus=old_signature"));
|
||||
assertFalse("不应包含 session_id", filtered.contains("session_id"));
|
||||
assertFalse("不应包含 random_cookie", filtered.contains("random_cookie"));
|
||||
|
||||
// 第二步:模拟刷新 __puus (从服务器获取新的签名)
|
||||
String newPuus = "__puus=refreshed_signature_from_server";
|
||||
String updated = CookieUtils.updateCookieValue(filtered, "__puus", newPuus);
|
||||
System.out.println("\n3. 刷新 __puus 后的 Cookie:");
|
||||
System.out.println(" " + updated);
|
||||
|
||||
// 验证更新结果
|
||||
assertTrue("应包含新的 __puus", updated.contains("__puus=refreshed_signature_from_server"));
|
||||
assertFalse("不应包含旧的 __puus", updated.contains("__puus=old_signature"));
|
||||
assertTrue("应保留 __pus", updated.contains("__pus=main_token_here"));
|
||||
|
||||
// 第三步:验证可以获取单个值
|
||||
String pusValue = CookieUtils.getCookieValue(updated, "__pus");
|
||||
String puusValue = CookieUtils.getCookieValue(updated, "__puus");
|
||||
System.out.println("\n4. 提取单个 Cookie 值:");
|
||||
System.out.println(" __pus = " + pusValue);
|
||||
System.out.println(" __puus = " + puusValue);
|
||||
|
||||
assertEquals("main_token_here", pusValue);
|
||||
assertEquals("refreshed_signature_from_server", puusValue);
|
||||
|
||||
System.out.println("\n✓ 复杂场景测试通过");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllUcQuarkCookieFields() {
|
||||
System.out.println("\n=== 测试所有 UC/夸克 Cookie 必需字段 ===");
|
||||
|
||||
// 包含所有必需字段的 Cookie
|
||||
String fullCookie = "__pus=token1; __kp=token2; __kps=token3; " +
|
||||
"__ktd=token4; __uid=token5; __puus=token6; " +
|
||||
"extra1=value1; extra2=value2";
|
||||
|
||||
String filtered = CookieUtils.filterUcQuarkCookie(fullCookie);
|
||||
|
||||
System.out.println("原始 Cookie: " + fullCookie);
|
||||
System.out.println("过滤后: " + filtered);
|
||||
System.out.println("\n验证必需字段:");
|
||||
|
||||
// 验证所有必需字段都被保留
|
||||
String[] requiredFields = {"__pus", "__kp", "__kps", "__ktd", "__uid", "__puus"};
|
||||
for (String field : requiredFields) {
|
||||
boolean contains = CookieUtils.containsKey(filtered, field);
|
||||
System.out.println(" - " + field + ": " + (contains ? "✓" : "✗"));
|
||||
assertTrue("应包含 " + field, contains);
|
||||
}
|
||||
|
||||
// 验证额外字段被过滤掉
|
||||
assertFalse("不应包含 extra1", filtered.contains("extra1"));
|
||||
assertFalse("不应包含 extra2", filtered.contains("extra2"));
|
||||
|
||||
System.out.println("\n✓ 所有字段测试通过");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
package cn.qaiu.parser.auth;
|
||||
|
||||
import cn.qaiu.util.CookieUtils;
|
||||
|
||||
/**
|
||||
* 手动测试 Cookie 工具类
|
||||
*/
|
||||
public class CookieUtilsManualTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("========================================");
|
||||
System.out.println(" Cookie 工具类手动测试");
|
||||
System.out.println("========================================\n");
|
||||
|
||||
testCookieFilter();
|
||||
testCookieGetValue();
|
||||
testCookieUpdate();
|
||||
testCookieContainsKey();
|
||||
testEmptyCookieHandling();
|
||||
testComplexScenario();
|
||||
testAllUcQuarkCookieFields();
|
||||
|
||||
System.out.println("\n========================================");
|
||||
System.out.println(" 所有测试通过! ✓");
|
||||
System.out.println("========================================");
|
||||
}
|
||||
|
||||
private static void testCookieFilter() {
|
||||
System.out.println("=== 测试 Cookie 过滤功能 ===");
|
||||
String fullCookie = "__pus=abc123; __kp=def456; other_cookie=xyz; __puus=token789; random=test; __uid=user001";
|
||||
String filtered = CookieUtils.filterUcQuarkCookie(fullCookie);
|
||||
|
||||
System.out.println("原始 Cookie: " + fullCookie);
|
||||
System.out.println("过滤后 Cookie: " + filtered);
|
||||
|
||||
assert filtered.contains("__pus=abc123") : "应包含 __pus";
|
||||
assert filtered.contains("__kp=def456") : "应包含 __kp";
|
||||
assert filtered.contains("__puus=token789") : "应包含 __puus";
|
||||
assert !filtered.contains("other_cookie") : "不应包含 other_cookie";
|
||||
assert !filtered.contains("random") : "不应包含 random";
|
||||
|
||||
System.out.println("✓ Cookie 过滤测试通过\n");
|
||||
}
|
||||
|
||||
private static void testCookieGetValue() {
|
||||
System.out.println("=== 测试获取 Cookie 值 ===");
|
||||
String cookie = "__pus=value1; __kp=value2; __puus=value3";
|
||||
|
||||
String pus = CookieUtils.getCookieValue(cookie, "__pus");
|
||||
String kp = CookieUtils.getCookieValue(cookie, "__kp");
|
||||
String puus = CookieUtils.getCookieValue(cookie, "__puus");
|
||||
String notexist = CookieUtils.getCookieValue(cookie, "notexist");
|
||||
|
||||
System.out.println("Cookie: " + cookie);
|
||||
System.out.println("__pus = " + pus);
|
||||
System.out.println("__kp = " + kp);
|
||||
System.out.println("__puus = " + puus);
|
||||
System.out.println("notexist = " + notexist);
|
||||
|
||||
assert "value1".equals(pus) : "__pus 应为 value1";
|
||||
assert "value2".equals(kp) : "__kp 应为 value2";
|
||||
assert "value3".equals(puus) : "__puus 应为 value3";
|
||||
assert notexist == null : "notexist 应为 null";
|
||||
|
||||
System.out.println("✓ 获取 Cookie 值测试通过\n");
|
||||
}
|
||||
|
||||
private static void testCookieUpdate() {
|
||||
System.out.println("=== 测试更新 Cookie ===");
|
||||
String cookie = "__pus=old_pus; __kp=value2";
|
||||
String updated = CookieUtils.updateCookieValue(cookie, "__puus", "__puus=new_puus_value");
|
||||
|
||||
System.out.println("更新前: " + cookie);
|
||||
System.out.println("更新后: " + updated);
|
||||
|
||||
assert updated.contains("__puus=new_puus_value") : "应包含新的 __puus";
|
||||
assert updated.contains("__pus=old_pus") : "应保留 __pus";
|
||||
assert updated.contains("__kp=value2") : "应保留 __kp";
|
||||
|
||||
// 测试替换已存在的值
|
||||
String cookie2 = "__pus=old_value; __kp=value2; __puus=old_puus";
|
||||
String updated2 = CookieUtils.updateCookieValue(cookie2, "__puus", "__puus=updated_puus");
|
||||
|
||||
System.out.println("替换测试 - 更新前: " + cookie2);
|
||||
System.out.println("替换测试 - 更新后: " + updated2);
|
||||
|
||||
assert updated2.contains("__puus=updated_puus") : "应包含更新的 __puus";
|
||||
assert !updated2.contains("__puus=old_puus") : "不应包含旧的 __puus";
|
||||
|
||||
System.out.println("✓ 更新 Cookie 测试通过\n");
|
||||
}
|
||||
|
||||
private static void testCookieContainsKey() {
|
||||
System.out.println("=== 测试检查 Cookie key 存在性 ===");
|
||||
String cookie = "__pus=value1; __kp=value2; __uid=user123";
|
||||
|
||||
boolean hasPus = CookieUtils.containsKey(cookie, "__pus");
|
||||
boolean hasKp = CookieUtils.containsKey(cookie, "__kp");
|
||||
boolean hasPuus = CookieUtils.containsKey(cookie, "__puus");
|
||||
boolean hasNotexist = CookieUtils.containsKey(cookie, "notexist");
|
||||
|
||||
System.out.println("Cookie: " + cookie);
|
||||
System.out.println("containsKey(__pus): " + hasPus);
|
||||
System.out.println("containsKey(__kp): " + hasKp);
|
||||
System.out.println("containsKey(__puus): " + hasPuus);
|
||||
System.out.println("containsKey(notexist): " + hasNotexist);
|
||||
|
||||
assert hasPus : "__pus 应存在";
|
||||
assert hasKp : "__kp 应存在";
|
||||
assert !hasPuus : "__puus 不应存在";
|
||||
assert !hasNotexist : "notexist 不应存在";
|
||||
|
||||
System.out.println("✓ 检查 Cookie key 测试通过\n");
|
||||
}
|
||||
|
||||
private static void testEmptyCookieHandling() {
|
||||
System.out.println("=== 测试空 Cookie 处理 ===");
|
||||
String emptyFiltered = CookieUtils.filterUcQuarkCookie("");
|
||||
String nullFiltered = CookieUtils.filterUcQuarkCookie(null);
|
||||
String emptyValue = CookieUtils.getCookieValue("", "__pus");
|
||||
String nullValue = CookieUtils.getCookieValue(null, "__pus");
|
||||
|
||||
System.out.println("filterUcQuarkCookie(''): '" + emptyFiltered + "'");
|
||||
System.out.println("filterUcQuarkCookie(null): '" + nullFiltered + "'");
|
||||
System.out.println("getCookieValue('', '__pus'): " + emptyValue);
|
||||
System.out.println("getCookieValue(null, '__pus'): " + nullValue);
|
||||
|
||||
assert "".equals(emptyFiltered) : "空字符串应返回空字符串";
|
||||
assert "".equals(nullFiltered) : "null 应返回空字符串";
|
||||
assert emptyValue == null : "空字符串的值应为 null";
|
||||
assert nullValue == null : "null 的值应为 null";
|
||||
|
||||
System.out.println("✓ 空 Cookie 处理测试通过\n");
|
||||
}
|
||||
|
||||
private static void testComplexScenario() {
|
||||
System.out.println("=== 测试复杂场景:模拟 UC/夸克 Cookie 处理流程 ===");
|
||||
|
||||
// 模拟从浏览器获取的完整 Cookie
|
||||
String browserCookie = "session_id=xxx; __pus=main_token_here; other=value; " +
|
||||
"__kp=key123; __kps=secret456; __ktd=token789; " +
|
||||
"__uid=user001; random_cookie=test; __puus=old_signature";
|
||||
|
||||
System.out.println("1. 浏览器原始 Cookie:");
|
||||
System.out.println(" " + browserCookie);
|
||||
|
||||
// 第一步:过滤出必要的字段
|
||||
String filtered = CookieUtils.filterUcQuarkCookie(browserCookie);
|
||||
System.out.println("\n2. 过滤后的 Cookie (只保留 UC/夸克必需字段):");
|
||||
System.out.println(" " + filtered);
|
||||
|
||||
assert filtered.contains("__pus=main_token_here") : "应包含 __pus";
|
||||
assert filtered.contains("__kp=key123") : "应包含 __kp";
|
||||
assert filtered.contains("__puus=old_signature") : "应包含 __puus";
|
||||
assert !filtered.contains("session_id") : "不应包含 session_id";
|
||||
assert !filtered.contains("random_cookie") : "不应包含 random_cookie";
|
||||
|
||||
// 第二步:模拟刷新 __puus
|
||||
String newPuus = "__puus=refreshed_signature_from_server";
|
||||
String updated = CookieUtils.updateCookieValue(filtered, "__puus", newPuus);
|
||||
System.out.println("\n3. 刷新 __puus 后的 Cookie:");
|
||||
System.out.println(" " + updated);
|
||||
|
||||
assert updated.contains("__puus=refreshed_signature_from_server") : "应包含新的 __puus";
|
||||
assert !updated.contains("__puus=old_signature") : "不应包含旧的 __puus";
|
||||
assert updated.contains("__pus=main_token_here") : "应保留 __pus";
|
||||
|
||||
// 第三步:验证可以获取单个值
|
||||
String pusValue = CookieUtils.getCookieValue(updated, "__pus");
|
||||
String puusValue = CookieUtils.getCookieValue(updated, "__puus");
|
||||
System.out.println("\n4. 提取单个 Cookie 值:");
|
||||
System.out.println(" __pus = " + pusValue);
|
||||
System.out.println(" __puus = " + puusValue);
|
||||
|
||||
assert "main_token_here".equals(pusValue) : "__pus 应为 main_token_here";
|
||||
assert "refreshed_signature_from_server".equals(puusValue) : "__puus 应为 refreshed_signature_from_server";
|
||||
|
||||
System.out.println("\n✓ 复杂场景测试通过\n");
|
||||
}
|
||||
|
||||
private static void testAllUcQuarkCookieFields() {
|
||||
System.out.println("=== 测试所有 UC/夸克 Cookie 必需字段 ===");
|
||||
|
||||
// 包含所有必需字段的 Cookie
|
||||
String fullCookie = "__pus=token1; __kp=token2; __kps=token3; " +
|
||||
"__ktd=token4; __uid=token5; __puus=token6; " +
|
||||
"extra1=value1; extra2=value2";
|
||||
|
||||
String filtered = CookieUtils.filterUcQuarkCookie(fullCookie);
|
||||
|
||||
System.out.println("原始 Cookie: " + fullCookie);
|
||||
System.out.println("过滤后: " + filtered);
|
||||
System.out.println("\n验证必需字段:");
|
||||
|
||||
// 验证所有必需字段都被保留
|
||||
String[] requiredFields = {"__pus", "__kp", "__kps", "__ktd", "__uid", "__puus"};
|
||||
for (String field : requiredFields) {
|
||||
boolean contains = CookieUtils.containsKey(filtered, field);
|
||||
System.out.println(" - " + field + ": " + (contains ? "✓" : "✗"));
|
||||
assert contains : "应包含 " + field;
|
||||
}
|
||||
|
||||
// 验证额外字段被过滤掉
|
||||
assert !filtered.contains("extra1") : "不应包含 extra1";
|
||||
assert !filtered.contains("extra2") : "不应包含 extra2";
|
||||
|
||||
System.out.println("\n✓ 所有字段测试通过\n");
|
||||
}
|
||||
}
|
||||
@@ -122,12 +122,12 @@ public class ClientLinkExample {
|
||||
|
||||
// 使用便捷工具类
|
||||
String curlCommand = ClientLinkUtils.generateCurlCommand(shareLinkInfo);
|
||||
String wgetCommand = ClientLinkUtils.generateWgetCommand(shareLinkInfo);
|
||||
String aria2Command = ClientLinkUtils.generateAria2Command(shareLinkInfo);
|
||||
String thunderLink = ClientLinkUtils.generateThunderLink(shareLinkInfo);
|
||||
|
||||
log.info("=== 使用便捷工具类生成的链接 ===");
|
||||
log.info("cURL命令: {}", curlCommand);
|
||||
log.info("wget命令: {}", wgetCommand);
|
||||
log.info("Aria2命令: {}", aria2Command);
|
||||
log.info("迅雷链接: {}", thunderLink);
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
package cn.qaiu.parser.clientlink;
|
||||
|
||||
import cn.qaiu.entity.ShareLinkInfo;
|
||||
import cn.qaiu.parser.clientlink.ClientLinkType;
|
||||
import cn.qaiu.parser.clientlink.DownloadLinkMeta;
|
||||
import cn.qaiu.parser.clientlink.impl.CurlLinkGenerator;
|
||||
import cn.qaiu.parser.clientlink.impl.ThunderLinkGenerator;
|
||||
import cn.qaiu.parser.clientlink.impl.Aria2LinkGenerator;
|
||||
import cn.qaiu.parser.clientlink.impl.PowerShellLinkGenerator;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* 客户端链接生成器功能测试
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
* Create at 2025/01/21
|
||||
*/
|
||||
public class ClientLinkGeneratorTest {
|
||||
|
||||
private ShareLinkInfo shareLinkInfo;
|
||||
private DownloadLinkMeta meta;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
// 创建测试用的 ShareLinkInfo
|
||||
shareLinkInfo = ShareLinkInfo.newBuilder()
|
||||
.type("test")
|
||||
.panName("测试网盘")
|
||||
.shareUrl("https://example.com/share/test")
|
||||
.build();
|
||||
|
||||
Map<String, Object> otherParam = new HashMap<>();
|
||||
otherParam.put("downloadUrl", "https://example.com/file.zip");
|
||||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Test Browser)");
|
||||
headers.put("Referer", "https://example.com/share/test");
|
||||
headers.put("Cookie", "session=abc123");
|
||||
otherParam.put("downloadHeaders", headers);
|
||||
|
||||
shareLinkInfo.setOtherParam(otherParam);
|
||||
|
||||
// 创建测试用的 DownloadLinkMeta
|
||||
meta = new DownloadLinkMeta("https://example.com/file.zip");
|
||||
meta.setFileName("test-file.zip");
|
||||
meta.setHeaders(headers);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCurlLinkGenerator() {
|
||||
CurlLinkGenerator generator = new CurlLinkGenerator();
|
||||
|
||||
String result = generator.generate(meta);
|
||||
|
||||
assertNotNull("cURL命令不应为空", result);
|
||||
assertTrue("应包含curl命令", result.contains("curl"));
|
||||
assertTrue("应包含下载URL", result.contains("https://example.com/file.zip"));
|
||||
assertTrue("应包含User-Agent头", result.contains("\"User-Agent: Mozilla/5.0 (Test Browser)\""));
|
||||
assertTrue("应包含Referer头", result.contains("\"Referer: https://example.com/share/test\""));
|
||||
assertTrue("应包含Cookie头", result.contains("\"Cookie: session=abc123\""));
|
||||
assertTrue("应包含输出文件名", result.contains("\"test-file.zip\""));
|
||||
assertTrue("应包含跟随重定向", result.contains("-L"));
|
||||
|
||||
assertEquals("类型应为CURL", ClientLinkType.CURL, generator.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThunderLinkGenerator() {
|
||||
ThunderLinkGenerator generator = new ThunderLinkGenerator();
|
||||
|
||||
String result = generator.generate(meta);
|
||||
|
||||
assertNotNull("迅雷链接不应为空", result);
|
||||
assertTrue("应以thunder://开头", result.startsWith("thunder://"));
|
||||
|
||||
// 验证Base64编码格式
|
||||
String encodedPart = result.substring("thunder://".length());
|
||||
assertNotNull("编码部分不应为空", encodedPart);
|
||||
assertFalse("编码部分不应为空字符串", encodedPart.isEmpty());
|
||||
|
||||
assertEquals("类型应为THUNDER", ClientLinkType.THUNDER, generator.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAria2LinkGenerator() {
|
||||
Aria2LinkGenerator generator = new Aria2LinkGenerator();
|
||||
|
||||
String result = generator.generate(meta);
|
||||
|
||||
assertNotNull("Aria2命令不应为空", result);
|
||||
assertTrue("应包含aria2c命令", result.contains("aria2c"));
|
||||
assertTrue("应包含下载URL", result.contains("https://example.com/file.zip"));
|
||||
assertTrue("应包含User-Agent头", result.contains("--header=\"User-Agent: Mozilla/5.0 (Test Browser)\""));
|
||||
assertTrue("应包含Referer头", result.contains("--header=\"Referer: https://example.com/share/test\""));
|
||||
assertTrue("应包含输出文件名", result.contains("--out=\"test-file.zip\""));
|
||||
assertTrue("应包含断点续传", result.contains("--continue"));
|
||||
|
||||
assertEquals("类型应为ARIA2", ClientLinkType.ARIA2, generator.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPowerShellLinkGenerator() {
|
||||
PowerShellLinkGenerator generator = new PowerShellLinkGenerator();
|
||||
|
||||
String result = generator.generate(meta);
|
||||
|
||||
assertNotNull("PowerShell命令不应为空", result);
|
||||
assertTrue("应包含WebRequestSession", result.contains("$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession"));
|
||||
assertTrue("应包含Invoke-WebRequest", result.contains("Invoke-WebRequest"));
|
||||
assertTrue("应包含-UseBasicParsing", result.contains("-UseBasicParsing"));
|
||||
assertTrue("应包含下载URL", result.contains("https://example.com/file.zip"));
|
||||
assertTrue("应包含User-Agent", result.contains("User-Agent"));
|
||||
assertTrue("应包含Referer", result.contains("Referer"));
|
||||
assertTrue("应包含Cookie", result.contains("Cookie"));
|
||||
assertTrue("应包含输出文件", result.contains("test-file.zip"));
|
||||
|
||||
assertEquals("类型应为POWERSHELL", ClientLinkType.POWERSHELL, generator.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPowerShellLinkGeneratorWithoutHeaders() {
|
||||
PowerShellLinkGenerator generator = new PowerShellLinkGenerator();
|
||||
|
||||
meta.setHeaders(new HashMap<>());
|
||||
String result = generator.generate(meta);
|
||||
|
||||
assertNotNull("PowerShell命令不应为空", result);
|
||||
assertTrue("应包含WebRequestSession", result.contains("$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession"));
|
||||
assertTrue("应包含Invoke-WebRequest", result.contains("Invoke-WebRequest"));
|
||||
assertTrue("应包含下载URL", result.contains("https://example.com/file.zip"));
|
||||
assertFalse("不应包含Headers", result.contains("-Headers @{"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPowerShellLinkGeneratorWithoutFileName() {
|
||||
PowerShellLinkGenerator generator = new PowerShellLinkGenerator();
|
||||
|
||||
meta.setFileName(null);
|
||||
String result = generator.generate(meta);
|
||||
|
||||
assertNotNull("PowerShell命令不应为空", result);
|
||||
assertTrue("应包含WebRequestSession", result.contains("$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession"));
|
||||
assertTrue("应包含Invoke-WebRequest", result.contains("Invoke-WebRequest"));
|
||||
assertTrue("应包含下载URL", result.contains("https://example.com/file.zip"));
|
||||
assertFalse("不应包含OutFile", result.contains("-OutFile"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPowerShellLinkGeneratorWithSpecialCharacters() {
|
||||
PowerShellLinkGenerator generator = new PowerShellLinkGenerator();
|
||||
|
||||
// 测试包含特殊字符的URL和请求头
|
||||
meta.setUrl("https://example.com/file with spaces.zip");
|
||||
Map<String, String> specialHeaders = new HashMap<>();
|
||||
specialHeaders.put("Custom-Header", "Value with \"quotes\" and $variables");
|
||||
meta.setHeaders(specialHeaders);
|
||||
|
||||
String result = generator.generate(meta);
|
||||
|
||||
assertNotNull("PowerShell命令不应为空", result);
|
||||
assertTrue("应包含转义的URL", result.contains("https://example.com/file with spaces.zip"));
|
||||
assertTrue("应包含转义的请求头", result.contains("Custom-Header"));
|
||||
assertTrue("应包含转义的引号", result.contains("`\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloadLinkMetaFromShareLinkInfo() {
|
||||
DownloadLinkMeta metaFromInfo = DownloadLinkMeta.fromShareLinkInfo(shareLinkInfo);
|
||||
|
||||
assertNotNull("从ShareLinkInfo创建的DownloadLinkMeta不应为空", metaFromInfo);
|
||||
assertEquals("URL应匹配", "https://example.com/file.zip", metaFromInfo.getUrl());
|
||||
assertEquals("Referer应匹配", "https://example.com/share/test", metaFromInfo.getReferer());
|
||||
assertEquals("User-Agent应匹配", "Mozilla/5.0 (Test Browser)", metaFromInfo.getUserAgent());
|
||||
|
||||
Map<String, String> headers = metaFromInfo.getHeaders();
|
||||
assertNotNull("请求头不应为空", headers);
|
||||
assertEquals("请求头数量应匹配", 3, headers.size());
|
||||
assertEquals("User-Agent应匹配", "Mozilla/5.0 (Test Browser)", headers.get("User-Agent"));
|
||||
assertEquals("Referer应匹配", "https://example.com/share/test", headers.get("Referer"));
|
||||
assertEquals("Cookie应匹配", "session=abc123", headers.get("Cookie"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientLinkGeneratorFactory() {
|
||||
Map<ClientLinkType, String> allLinks = ClientLinkGeneratorFactory.generateAll(shareLinkInfo);
|
||||
|
||||
assertNotNull("生成的链接集合不应为空", allLinks);
|
||||
assertFalse("生成的链接集合不应为空", allLinks.isEmpty());
|
||||
|
||||
// 检查是否生成了主要类型的链接
|
||||
assertTrue("应生成cURL链接", allLinks.containsKey(ClientLinkType.CURL));
|
||||
assertTrue("应生成迅雷链接", allLinks.containsKey(ClientLinkType.THUNDER));
|
||||
assertTrue("应生成Aria2链接", allLinks.containsKey(ClientLinkType.ARIA2));
|
||||
assertTrue("应生成wget链接", allLinks.containsKey(ClientLinkType.WGET));
|
||||
assertTrue("应生成PowerShell链接", allLinks.containsKey(ClientLinkType.POWERSHELL));
|
||||
|
||||
// 验证生成的链接不为空
|
||||
assertNotNull("cURL链接不应为空", allLinks.get(ClientLinkType.CURL));
|
||||
assertNotNull("迅雷链接不应为空", allLinks.get(ClientLinkType.THUNDER));
|
||||
assertNotNull("Aria2链接不应为空", allLinks.get(ClientLinkType.ARIA2));
|
||||
assertNotNull("wget链接不应为空", allLinks.get(ClientLinkType.WGET));
|
||||
assertNotNull("PowerShell链接不应为空", allLinks.get(ClientLinkType.POWERSHELL));
|
||||
|
||||
assertFalse("cURL链接不应为空字符串", allLinks.get(ClientLinkType.CURL).trim().isEmpty());
|
||||
assertFalse("迅雷链接不应为空字符串", allLinks.get(ClientLinkType.THUNDER).trim().isEmpty());
|
||||
assertFalse("Aria2链接不应为空字符串", allLinks.get(ClientLinkType.ARIA2).trim().isEmpty());
|
||||
assertFalse("wget链接不应为空字符串", allLinks.get(ClientLinkType.WGET).trim().isEmpty());
|
||||
assertFalse("PowerShell链接不应为空字符串", allLinks.get(ClientLinkType.POWERSHELL).trim().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientLinkUtils() {
|
||||
String curlCommand = ClientLinkUtils.generateCurlCommand(shareLinkInfo);
|
||||
String thunderLink = ClientLinkUtils.generateThunderLink(shareLinkInfo);
|
||||
String aria2Command = ClientLinkUtils.generateAria2Command(shareLinkInfo);
|
||||
String powershellCommand = ClientLinkUtils.generatePowerShellCommand(shareLinkInfo);
|
||||
|
||||
assertNotNull("cURL命令不应为空", curlCommand);
|
||||
assertNotNull("迅雷链接不应为空", thunderLink);
|
||||
assertNotNull("Aria2命令不应为空", aria2Command);
|
||||
assertNotNull("PowerShell命令不应为空", powershellCommand);
|
||||
|
||||
assertTrue("cURL命令应包含curl", curlCommand.contains("curl"));
|
||||
assertTrue("迅雷链接应以thunder://开头", thunderLink.startsWith("thunder://"));
|
||||
assertTrue("Aria2命令应包含aria2c", aria2Command.contains("aria2c"));
|
||||
assertTrue("PowerShell命令应包含Invoke-WebRequest", powershellCommand.contains("Invoke-WebRequest"));
|
||||
|
||||
// 测试元数据有效性检查
|
||||
assertTrue("应检测到有效的下载元数据", ClientLinkUtils.hasValidDownloadMeta(shareLinkInfo));
|
||||
|
||||
// 测试无效元数据
|
||||
ShareLinkInfo emptyInfo = ShareLinkInfo.newBuilder().build();
|
||||
assertFalse("应检测到无效的下载元数据", ClientLinkUtils.hasValidDownloadMeta(emptyInfo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullAndEmptyHandling() {
|
||||
// 测试空URL
|
||||
DownloadLinkMeta emptyMeta = new DownloadLinkMeta("");
|
||||
CurlLinkGenerator generator = new CurlLinkGenerator();
|
||||
|
||||
String result = generator.generate(emptyMeta);
|
||||
assertNull("空URL应返回null", result);
|
||||
|
||||
// 测试null元数据
|
||||
result = generator.generate(null);
|
||||
assertNull("null元数据应返回null", result);
|
||||
|
||||
// 测试null ShareLinkInfo
|
||||
String curlResult = ClientLinkUtils.generateCurlCommand(null);
|
||||
assertNull("null ShareLinkInfo应返回null", curlResult);
|
||||
|
||||
Map<ClientLinkType, String> allResult = ClientLinkUtils.generateAllClientLinks(null);
|
||||
assertTrue("null ShareLinkInfo应返回空集合", allResult.isEmpty());
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package cn.qaiu.parser.clientlink;
|
||||
|
||||
import cn.qaiu.entity.ShareLinkInfo;
|
||||
import cn.qaiu.parser.clientlink.ClientLinkType;
|
||||
import cn.qaiu.parser.clientlink.DownloadLinkMeta;
|
||||
import cn.qaiu.parser.clientlink.impl.PowerShellLinkGenerator;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* PowerShell 生成器示例
|
||||
*
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
* Create at 2025/01/21
|
||||
*/
|
||||
public class PowerShellExample {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 创建测试数据
|
||||
DownloadLinkMeta meta = new DownloadLinkMeta("https://example.com/file.zip");
|
||||
meta.setFileName("test-file.zip");
|
||||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||
headers.put("Referer", "https://example.com/share/test");
|
||||
headers.put("Cookie", "session=abc123");
|
||||
headers.put("Accept", "text/html,application/xhtml+xml");
|
||||
meta.setHeaders(headers);
|
||||
|
||||
// 生成 PowerShell 命令
|
||||
PowerShellLinkGenerator generator = new PowerShellLinkGenerator();
|
||||
String powershellCommand = generator.generate(meta);
|
||||
|
||||
System.out.println("=== 生成的 PowerShell 命令 ===");
|
||||
System.out.println(powershellCommand);
|
||||
System.out.println();
|
||||
|
||||
// 测试特殊字符转义
|
||||
meta.setUrl("https://example.com/file with spaces.zip");
|
||||
Map<String, String> specialHeaders = new HashMap<>();
|
||||
specialHeaders.put("Custom-Header", "Value with \"quotes\" and $variables");
|
||||
meta.setHeaders(specialHeaders);
|
||||
|
||||
String escapedCommand = generator.generate(meta);
|
||||
|
||||
System.out.println("=== 包含特殊字符的 PowerShell 命令 ===");
|
||||
System.out.println(escapedCommand);
|
||||
System.out.println();
|
||||
|
||||
// 使用 ClientLinkUtils
|
||||
ShareLinkInfo shareLinkInfo = ShareLinkInfo.newBuilder()
|
||||
.type("test")
|
||||
.panName("测试网盘")
|
||||
.shareUrl("https://example.com/share/test")
|
||||
.build();
|
||||
|
||||
Map<String, Object> otherParam = new HashMap<>();
|
||||
otherParam.put("downloadUrl", "https://example.com/file.zip");
|
||||
otherParam.put("downloadHeaders", headers);
|
||||
shareLinkInfo.setOtherParam(otherParam);
|
||||
|
||||
String utilsCommand = ClientLinkUtils.generatePowerShellCommand(shareLinkInfo);
|
||||
|
||||
System.out.println("=== 使用 ClientLinkUtils 生成的 PowerShell 命令 ===");
|
||||
System.out.println(utilsCommand);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package cn.qaiu.parser.clientlink;
|
||||
|
||||
import cn.qaiu.entity.FileInfo;
|
||||
import cn.qaiu.entity.ShareLinkInfo;
|
||||
import cn.qaiu.parser.PanDomainTemplate;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* UC和夸克网盘客户端链接生成测试
|
||||
* 测试在有下载链接和请求头的情况下,是否能正确生成下载命令
|
||||
*/
|
||||
public class UcQkClientLinkTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("========================================");
|
||||
System.out.println(" UC/夸克网盘客户端链接生成测试");
|
||||
System.out.println("========================================\n");
|
||||
|
||||
// 测试 UC 网盘
|
||||
testUcClientLinks();
|
||||
|
||||
// 测试夸克网盘
|
||||
testQkClientLinks();
|
||||
|
||||
System.out.println("\n========================================");
|
||||
System.out.println(" 测试完成");
|
||||
System.out.println("========================================");
|
||||
}
|
||||
|
||||
private static void testUcClientLinks() {
|
||||
System.out.println("=== 测试 UC 网盘客户端链接生成 ===\n");
|
||||
|
||||
// 创建 ShareLinkInfo (使用 Builder)
|
||||
ShareLinkInfo info = ShareLinkInfo.newBuilder()
|
||||
.type("uc")
|
||||
.panName(PanDomainTemplate.UC.getDisplayName())
|
||||
.shareKey("test123")
|
||||
.build();
|
||||
|
||||
// 模拟下载链接(UC网盘的真实下载链接格式)
|
||||
String downloadUrl = "https://pc-api.uc.cn/1/clouddrive/file/download?xxx";
|
||||
info.getOtherParam().put("downloadUrl", downloadUrl);
|
||||
|
||||
// 模拟下载请求头(包含Cookie)
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Cookie", "__pus=5e2bfe93fc55175482cd81dbafb41586AARGIGToqJ7RFMUETPbInASaHMcrrwTch6A6cjwBQQF0gKWZZxV20iixkInaK3AQrW+zsggDwifeq2BZ6fOBsj1N; __kp=72747319-24ad-44da-85a9-133fedd72818; __kps=AASxYmDMULu4nzmEK/wFzK3I; __ktd=dvy3qySVr8aXEqUuxMJydA==; __uid=AASxYmDMULu4nzmEK/wFzK3I; __puus=bdb2e15d24f1a15fe2b5e108b44f0805AAR498zI4bjrVRD3mNor9LX8YbixADr2C4YebqDb1fvtySVLiF3VgyASPRi/VSfMikDVd3yHUtbqP3ZwAteImXbevPo84hloWgCG0qCouDie3PKBIXq4+UxiXay2GHtst71wVq7ODiWV3OzzazpYgtGqTjep8F4BWtwdwtCjQz6l6OHVYy/LkTe3/6eeAreiRNU=");
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||
headers.put("Referer", "https://drive.uc.cn/");
|
||||
info.getOtherParam().put("downloadHeaders", headers);
|
||||
|
||||
// 设置文件信息(通过otherParam)
|
||||
FileInfo fileInfo = new FileInfo();
|
||||
fileInfo.setFileName("测试文件.zip");
|
||||
info.getOtherParam().put("fileInfo", fileInfo);
|
||||
|
||||
// 生成客户端链接
|
||||
Map<ClientLinkType, String> clientLinks = ClientLinkGeneratorFactory.generateAll(info);
|
||||
|
||||
if (clientLinks.isEmpty()) {
|
||||
System.out.println("❌ 未能生成任何客户端链接\n");
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("✅ 成功生成 " + clientLinks.size() + " 个客户端链接:\n");
|
||||
|
||||
for (Map.Entry<ClientLinkType, String> entry : clientLinks.entrySet()) {
|
||||
ClientLinkType type = entry.getKey();
|
||||
String link = entry.getValue();
|
||||
|
||||
System.out.println("【" + type.getDisplayName() + "】");
|
||||
System.out.println(link);
|
||||
System.out.println();
|
||||
|
||||
// 验证链接格式
|
||||
validateLink(type, link, "UC");
|
||||
}
|
||||
}
|
||||
|
||||
private static void testQkClientLinks() {
|
||||
System.out.println("=== 测试夸克网盘客户端链接生成 ===\n");
|
||||
|
||||
// 创建 ShareLinkInfo (使用 Builder)
|
||||
ShareLinkInfo info = ShareLinkInfo.newBuilder()
|
||||
.type("qk")
|
||||
.panName(PanDomainTemplate.QK.getDisplayName())
|
||||
.shareKey("test456")
|
||||
.build();
|
||||
|
||||
// 模拟下载链接(夸克网盘的真实下载链接格式)
|
||||
String downloadUrl = "https://drive-pc.quark.cn/1/clouddrive/file/download?xxx";
|
||||
info.getOtherParam().put("downloadUrl", downloadUrl);
|
||||
|
||||
// 模拟下载请求头(包含Cookie)
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Cookie", "__pus=abc123def456; __kp=ghi789jkl012; __kps=mno345pqr678; __ktd=stu901vwx234; __uid=yza567bcd890; __puus=efg123hij456");
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||
headers.put("Referer", "https://pan.quark.cn/");
|
||||
info.getOtherParam().put("downloadHeaders", headers);
|
||||
|
||||
// 设置文件信息(通过otherParam)
|
||||
FileInfo fileInfo = new FileInfo();
|
||||
fileInfo.setFileName("测试文件.mp4");
|
||||
info.getOtherParam().put("fileInfo", fileInfo);
|
||||
|
||||
// 生成客户端链接
|
||||
Map<ClientLinkType, String> clientLinks = ClientLinkGeneratorFactory.generateAll(info);
|
||||
|
||||
if (clientLinks.isEmpty()) {
|
||||
System.out.println("❌ 未能生成任何客户端链接\n");
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("✅ 成功生成 " + clientLinks.size() + " 个客户端链接:\n");
|
||||
|
||||
for (Map.Entry<ClientLinkType, String> entry : clientLinks.entrySet()) {
|
||||
ClientLinkType type = entry.getKey();
|
||||
String link = entry.getValue();
|
||||
|
||||
System.out.println("【" + type.getDisplayName() + "】");
|
||||
System.out.println(link);
|
||||
System.out.println();
|
||||
|
||||
// 验证链接格式
|
||||
validateLink(type, link, "夸克");
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateLink(ClientLinkType type, String link, String panName) {
|
||||
boolean valid = true;
|
||||
StringBuilder issues = new StringBuilder();
|
||||
|
||||
switch (type) {
|
||||
case CURL:
|
||||
if (!link.startsWith("curl ")) {
|
||||
valid = false;
|
||||
issues.append("不是以 'curl ' 开头; ");
|
||||
}
|
||||
if (!link.contains("--header \"Cookie:")) {
|
||||
valid = false;
|
||||
issues.append("缺少 Cookie 请求头; ");
|
||||
}
|
||||
if (!link.contains("--output")) {
|
||||
valid = false;
|
||||
issues.append("缺少输出文件名; ");
|
||||
}
|
||||
break;
|
||||
|
||||
case ARIA2:
|
||||
if (!link.contains("aria2c")) {
|
||||
valid = false;
|
||||
issues.append("不包含 'aria2c'; ");
|
||||
}
|
||||
if (!link.contains("--header=\"Cookie:")) {
|
||||
valid = false;
|
||||
issues.append("缺少 Cookie 请求头; ");
|
||||
}
|
||||
if (!link.contains("--out=")) {
|
||||
valid = false;
|
||||
issues.append("缺少输出文件名; ");
|
||||
}
|
||||
break;
|
||||
|
||||
case THUNDER:
|
||||
if (!link.startsWith("thunder://")) {
|
||||
valid = false;
|
||||
issues.append("不是以 'thunder://' 开头; ");
|
||||
}
|
||||
// 迅雷不支持 Cookie,所以不检查
|
||||
break;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
System.out.println(" ✓ " + panName + "的" + type.getDisplayName() + "格式验证通过");
|
||||
} else {
|
||||
System.out.println(" ⚠️ " + panName + "的" + type.getDisplayName() + "格式异常: " + issues);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package cn.qaiu.parser.impl;
|
||||
|
||||
import cn.qaiu.entity.ShareLinkInfo;
|
||||
import io.vertx.core.MultiMap;
|
||||
import io.vertx.core.http.impl.headers.HeadersMultiMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* UC 和夸克网盘工具类验证测试
|
||||
*/
|
||||
public class UcQkToolValidationTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("========================================");
|
||||
System.out.println(" UC/夸克网盘工具类验证测试");
|
||||
System.out.println("========================================\n");
|
||||
|
||||
testQkToolWithAuth();
|
||||
testUcToolWithAuth();
|
||||
testQkToolWithoutAuth();
|
||||
testUcToolWithoutAuth();
|
||||
|
||||
System.out.println("\n========================================");
|
||||
System.out.println(" 所有验证通过! ✓");
|
||||
System.out.println("========================================");
|
||||
}
|
||||
|
||||
private static void testQkToolWithAuth() {
|
||||
System.out.println("=== 测试夸克网盘工具类(带认证)===");
|
||||
|
||||
try {
|
||||
// 创建认证配置
|
||||
MultiMap auths = new HeadersMultiMap();
|
||||
auths.set("cookie", "__pus=test_token; __kp=key123; __kps=secret; __puus=signature");
|
||||
|
||||
Map<String, Object> otherParam = new HashMap<>();
|
||||
otherParam.put("auths", auths);
|
||||
|
||||
// 创建分享链接信息
|
||||
ShareLinkInfo shareLinkInfo = ShareLinkInfo.newBuilder()
|
||||
.type("QK")
|
||||
.panName("夸克网盘")
|
||||
.shareKey("test_key")
|
||||
.shareUrl("https://pan.quark.cn/s/test123")
|
||||
.build();
|
||||
shareLinkInfo.setOtherParam(otherParam);
|
||||
|
||||
// 创建工具类实例
|
||||
QkTool qkTool = new QkTool(shareLinkInfo);
|
||||
|
||||
System.out.println("✓ 夸克网盘工具类实例创建成功");
|
||||
System.out.println(" - 已配置认证信息");
|
||||
System.out.println(" - Cookie 已过滤和应用\n");
|
||||
} catch (Exception e) {
|
||||
System.err.println("✗ 夸克网盘工具类测试失败: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void testUcToolWithAuth() {
|
||||
System.out.println("=== 测试 UC 网盘工具类(带认证)===");
|
||||
|
||||
try {
|
||||
// 创建认证配置
|
||||
MultiMap auths = new HeadersMultiMap();
|
||||
auths.set("cookie", "__pus=uc_token; __kp=uc_key; __uid=user001; __puus=uc_sig");
|
||||
|
||||
Map<String, Object> otherParam = new HashMap<>();
|
||||
otherParam.put("auths", auths);
|
||||
|
||||
// 创建分享链接信息
|
||||
ShareLinkInfo shareLinkInfo = ShareLinkInfo.newBuilder()
|
||||
.type("UC")
|
||||
.panName("UC网盘")
|
||||
.shareKey("uc_key_123")
|
||||
.shareUrl("https://fast.uc.cn/s/abc123")
|
||||
.build();
|
||||
shareLinkInfo.setOtherParam(otherParam);
|
||||
|
||||
// 创建工具类实例
|
||||
UcTool ucTool = new UcTool(shareLinkInfo);
|
||||
|
||||
System.out.println("✓ UC 网盘工具类实例创建成功");
|
||||
System.out.println(" - 已配置认证信息");
|
||||
System.out.println(" - Cookie 已过滤和应用\n");
|
||||
} catch (Exception e) {
|
||||
System.err.println("✗ UC 网盘工具类测试失败: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void testQkToolWithoutAuth() {
|
||||
System.out.println("=== 测试夸克网盘工具类(无认证)===");
|
||||
|
||||
try {
|
||||
// 创建分享链接信息(无认证)
|
||||
ShareLinkInfo shareLinkInfo = ShareLinkInfo.newBuilder()
|
||||
.type("QK")
|
||||
.panName("夸克网盘")
|
||||
.shareKey("test_key_no_auth")
|
||||
.shareUrl("https://pan.quark.cn/s/test456")
|
||||
.build();
|
||||
|
||||
// 创建工具类实例
|
||||
QkTool qkTool = new QkTool(shareLinkInfo);
|
||||
|
||||
System.out.println("✓ 夸克网盘工具类实例创建成功(无认证)");
|
||||
System.out.println(" - 应该使用默认请求头\n");
|
||||
} catch (Exception e) {
|
||||
System.err.println("✗ 夸克网盘工具类(无认证)测试失败: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void testUcToolWithoutAuth() {
|
||||
System.out.println("=== 测试 UC 网盘工具类(无认证)===");
|
||||
|
||||
try {
|
||||
// 创建分享链接信息(无认证)
|
||||
ShareLinkInfo shareLinkInfo = ShareLinkInfo.newBuilder()
|
||||
.type("UC")
|
||||
.panName("UC网盘")
|
||||
.shareKey("uc_no_auth")
|
||||
.shareUrl("https://fast.uc.cn/s/def456")
|
||||
.build();
|
||||
|
||||
// 创建工具类实例
|
||||
UcTool ucTool = new UcTool(shareLinkInfo);
|
||||
|
||||
System.out.println("✓ UC 网盘工具类实例创建成功(无认证)");
|
||||
System.out.println(" - 应该使用默认请求头\n");
|
||||
} catch (Exception e) {
|
||||
System.err.println("✗ UC 网盘工具类(无认证)测试失败: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
package cn.qaiu.parser.integration;
|
||||
|
||||
import cn.qaiu.entity.ShareLinkInfo;
|
||||
import cn.qaiu.parser.IPanTool;
|
||||
import cn.qaiu.parser.ParserCreate;
|
||||
import io.vertx.core.MultiMap;
|
||||
import io.vertx.core.http.impl.headers.HeadersMultiMap;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 带认证的解析集成测试
|
||||
*
|
||||
* 使用方式:
|
||||
* 1. 在 src/test/resources/auth-test.properties 中配置认证信息
|
||||
* 2. 运行测试
|
||||
*
|
||||
* 配置文件格式:
|
||||
* qk.cookie=__pus=xxx; __kp=xxx; ...
|
||||
* qk.url=https://pan.quark.cn/s/xxx
|
||||
* uc.cookie=__pus=xxx; __kp=xxx; ...
|
||||
* uc.url=https://fast.uc.cn/s/xxx
|
||||
* fj.cookie=your_cookie_here
|
||||
* fj.url=https://share.feijipan.com/s/xxx
|
||||
* fj.pwd=1234
|
||||
*/
|
||||
public class AuthParseIntegrationTest {
|
||||
|
||||
private static final String CONFIG_FILE = "src/test/resources/auth-test.properties";
|
||||
private static Properties config;
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("========================================");
|
||||
System.out.println(" 带认证的解析集成测试");
|
||||
System.out.println("========================================\n");
|
||||
|
||||
// 加载配置
|
||||
if (!loadConfig()) {
|
||||
System.err.println("❌ 无法加载配置文件: " + CONFIG_FILE);
|
||||
System.out.println("\n请创建配置文件并添加认证信息:");
|
||||
printConfigExample();
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("✓ 配置文件加载成功\n");
|
||||
|
||||
// 测试夸克网盘
|
||||
if (hasConfig("qk")) {
|
||||
testQuark();
|
||||
} else {
|
||||
System.out.println("⏭ 跳过夸克网盘测试(未配置)\n");
|
||||
}
|
||||
|
||||
// 测试 UC 网盘
|
||||
if (hasConfig("uc")) {
|
||||
testUc();
|
||||
} else {
|
||||
System.out.println("⏭ 跳过 UC 网盘测试(未配置)\n");
|
||||
}
|
||||
|
||||
// 测试小飞机网盘
|
||||
if (hasConfig("fj")) {
|
||||
testFeiji();
|
||||
} else {
|
||||
System.out.println("⏭ 跳过小飞机网盘测试(未配置)\n");
|
||||
}
|
||||
|
||||
System.out.println("========================================");
|
||||
System.out.println(" 集成测试完成");
|
||||
System.out.println("========================================");
|
||||
|
||||
// 给异步操作一些时间完成
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
private static boolean loadConfig() {
|
||||
config = new Properties();
|
||||
try (FileReader reader = new FileReader(CONFIG_FILE)) {
|
||||
config.load(reader);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasConfig(String prefix) {
|
||||
return config.containsKey(prefix + ".url");
|
||||
}
|
||||
|
||||
private static String getConfig(String key) {
|
||||
return config.getProperty(key, "");
|
||||
}
|
||||
|
||||
private static void testQuark() {
|
||||
System.out.println("=== 测试夸克网盘解析(带认证)===");
|
||||
|
||||
String url = getConfig("qk.url");
|
||||
String cookie = getConfig("qk.cookie");
|
||||
String pwd = getConfig("qk.pwd");
|
||||
|
||||
System.out.println("分享链接: " + url);
|
||||
System.out.println("Cookie: " + maskCookie(cookie));
|
||||
if (!pwd.isEmpty()) {
|
||||
System.out.println("密码: " + pwd);
|
||||
}
|
||||
|
||||
try {
|
||||
// 创建认证配置
|
||||
MultiMap auths = new HeadersMultiMap();
|
||||
auths.set("cookie", cookie);
|
||||
|
||||
Map<String, Object> otherParam = new HashMap<>();
|
||||
otherParam.put("auths", auths);
|
||||
|
||||
// 创建解析器
|
||||
ParserCreate parserCreate = ParserCreate.fromShareUrl(url);
|
||||
ShareLinkInfo shareLinkInfo = parserCreate.getShareLinkInfo();
|
||||
if (!pwd.isEmpty()) {
|
||||
shareLinkInfo.setSharePassword(pwd);
|
||||
}
|
||||
shareLinkInfo.setOtherParam(otherParam);
|
||||
|
||||
IPanTool tool = parserCreate.createTool();
|
||||
|
||||
System.out.println("\n开始解析...");
|
||||
|
||||
// 异步解析
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
final long startTime = System.currentTimeMillis();
|
||||
|
||||
tool.parse().onSuccess(result -> {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
System.out.println("\n✅ 夸克网盘解析成功!");
|
||||
System.out.println("耗时: " + duration + "ms");
|
||||
System.out.println("直链: " + result);
|
||||
|
||||
// 验证直链格式
|
||||
if (result != null && result.startsWith("http")) {
|
||||
System.out.println("✓ 直链格式正确");
|
||||
} else {
|
||||
System.out.println("⚠️ 直链格式异常");
|
||||
}
|
||||
latch.countDown();
|
||||
}).onFailure(error -> {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
System.out.println("\n❌ 夸克网盘解析失败!");
|
||||
System.out.println("耗时: " + duration + "ms");
|
||||
System.out.println("错误: " + error.getMessage());
|
||||
if (error.getCause() != null) {
|
||||
System.out.println("原因: " + error.getCause().getMessage());
|
||||
}
|
||||
latch.countDown();
|
||||
});
|
||||
|
||||
// 等待结果(最多30秒)
|
||||
if (!latch.await(30, TimeUnit.SECONDS)) {
|
||||
System.out.println("\n⏱️ 解析超时(30秒)");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
System.out.println("\n❌ 测试异常: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
private static void testUc() {
|
||||
System.out.println("=== 测试 UC 网盘解析(带认证)===");
|
||||
|
||||
String url = getConfig("uc.url");
|
||||
String cookie = getConfig("uc.cookie");
|
||||
String pwd = getConfig("uc.pwd");
|
||||
|
||||
System.out.println("分享链接: " + url);
|
||||
System.out.println("Cookie: " + maskCookie(cookie));
|
||||
if (!pwd.isEmpty()) {
|
||||
System.out.println("密码: " + pwd);
|
||||
}
|
||||
|
||||
try {
|
||||
// 创建认证配置
|
||||
MultiMap auths = new HeadersMultiMap();
|
||||
auths.set("cookie", cookie);
|
||||
|
||||
Map<String, Object> otherParam = new HashMap<>();
|
||||
otherParam.put("auths", auths);
|
||||
|
||||
// 创建解析器
|
||||
ParserCreate parserCreate = ParserCreate.fromShareUrl(url);
|
||||
ShareLinkInfo shareLinkInfo = parserCreate.getShareLinkInfo();
|
||||
if (!pwd.isEmpty()) {
|
||||
shareLinkInfo.setSharePassword(pwd);
|
||||
}
|
||||
shareLinkInfo.setOtherParam(otherParam);
|
||||
|
||||
IPanTool tool = parserCreate.createTool();
|
||||
|
||||
System.out.println("\n开始解析...");
|
||||
|
||||
// 异步解析
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
final long startTime = System.currentTimeMillis();
|
||||
|
||||
tool.parse().onSuccess(result -> {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
System.out.println("\n✅ UC 网盘解析成功!");
|
||||
System.out.println("耗时: " + duration + "ms");
|
||||
System.out.println("直链: " + result);
|
||||
|
||||
// 验证直链格式
|
||||
if (result != null && result.startsWith("http")) {
|
||||
System.out.println("✓ 直链格式正确");
|
||||
} else {
|
||||
System.out.println("⚠️ 直链格式异常");
|
||||
}
|
||||
latch.countDown();
|
||||
}).onFailure(error -> {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
System.out.println("\n❌ UC 网盘解析失败!");
|
||||
System.out.println("耗时: " + duration + "ms");
|
||||
System.out.println("错误: " + error.getMessage());
|
||||
if (error.getCause() != null) {
|
||||
System.out.println("原因: " + error.getCause().getMessage());
|
||||
}
|
||||
latch.countDown();
|
||||
});
|
||||
|
||||
// 等待结果(最多30秒)
|
||||
if (!latch.await(30, TimeUnit.SECONDS)) {
|
||||
System.out.println("\n⏱️ 解析超时(30秒)");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
System.out.println("\n❌ 测试异常: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
private static void testFeiji() {
|
||||
System.out.println("=== 测试小飞机网盘解析(带认证)===");
|
||||
|
||||
String url = getConfig("fj.url");
|
||||
String username = getConfig("fj.username");
|
||||
String password = getConfig("fj.password");
|
||||
String pwd = getConfig("fj.pwd");
|
||||
|
||||
System.out.println("分享链接: " + url);
|
||||
System.out.println("用户名: " + (username.isEmpty() ? "无" : username));
|
||||
System.out.println("密码: " + (password.isEmpty() ? "无" : "******"));
|
||||
if (!pwd.isEmpty()) {
|
||||
System.out.println("提取码: " + pwd);
|
||||
}
|
||||
|
||||
try {
|
||||
// 创建认证配置
|
||||
MultiMap auths = new HeadersMultiMap();
|
||||
if (!username.isEmpty() && !password.isEmpty()) {
|
||||
auths.set("username", username);
|
||||
auths.set("password", password);
|
||||
}
|
||||
|
||||
Map<String, Object> otherParam = new HashMap<>();
|
||||
if (!username.isEmpty()) {
|
||||
otherParam.put("auths", auths);
|
||||
}
|
||||
|
||||
// 创建解析器
|
||||
ParserCreate parserCreate = ParserCreate.fromShareUrl(url);
|
||||
ShareLinkInfo shareLinkInfo = parserCreate.getShareLinkInfo();
|
||||
if (!pwd.isEmpty()) {
|
||||
shareLinkInfo.setSharePassword(pwd);
|
||||
}
|
||||
// 设置认证参数
|
||||
if (!username.isEmpty()) {
|
||||
shareLinkInfo.setOtherParam(otherParam);
|
||||
}
|
||||
|
||||
IPanTool tool = parserCreate.createTool();
|
||||
|
||||
System.out.println("\n开始解析...");
|
||||
|
||||
// 异步解析
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
final long startTime = System.currentTimeMillis();
|
||||
|
||||
tool.parse().onSuccess(result -> {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
System.out.println("\n✅ 小飞机网盘解析成功!");
|
||||
System.out.println("耗时: " + duration + "ms");
|
||||
System.out.println("直链: " + result);
|
||||
|
||||
// 验证直链格式
|
||||
if (result != null && result.startsWith("http")) {
|
||||
System.out.println("✓ 直链格式正确");
|
||||
} else {
|
||||
System.out.println("⚠️ 直链格式异常");
|
||||
}
|
||||
latch.countDown();
|
||||
}).onFailure(error -> {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
System.out.println("\n❌ 小飞机网盘解析失败!");
|
||||
System.out.println("耗时: " + duration + "ms");
|
||||
System.out.println("错误: " + error.getMessage());
|
||||
if (error.getCause() != null) {
|
||||
System.out.println("原因: " + error.getCause().getMessage());
|
||||
}
|
||||
latch.countDown();
|
||||
});
|
||||
|
||||
// 等待结果(最多30秒)
|
||||
if (!latch.await(30, TimeUnit.SECONDS)) {
|
||||
System.out.println("\n⏱️ 解析超时(30秒)");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
System.out.println("\n❌ 测试异常: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
private static String maskCookie(String cookie) {
|
||||
if (cookie == null || cookie.isEmpty()) {
|
||||
return "(未配置)";
|
||||
}
|
||||
if (cookie.length() <= 20) {
|
||||
return cookie.substring(0, Math.min(10, cookie.length())) + "...";
|
||||
}
|
||||
return cookie.substring(0, 10) + "..." + cookie.substring(cookie.length() - 10);
|
||||
}
|
||||
|
||||
private static void printConfigExample() {
|
||||
System.out.println("\n配置文件示例 (" + CONFIG_FILE + "):");
|
||||
System.out.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||
System.out.println("# 夸克网盘配置");
|
||||
System.out.println("qk.cookie=__pus=xxx; __kp=xxx; __kps=xxx; __ktd=xxx; __uid=xxx; __puus=xxx");
|
||||
System.out.println("qk.url=https://pan.quark.cn/s/xxxxxxxxxx");
|
||||
System.out.println("qk.pwd=");
|
||||
System.out.println();
|
||||
System.out.println("# UC 网盘配置");
|
||||
System.out.println("uc.cookie=__pus=xxx; __kp=xxx; __kps=xxx; __ktd=xxx; __uid=xxx; __puus=xxx");
|
||||
System.out.println("uc.url=https://fast.uc.cn/s/xxxxxxxxxx");
|
||||
System.out.println("uc.pwd=");
|
||||
System.out.println();
|
||||
System.out.println("# 小飞机网盘配置(大文件需要认证)");
|
||||
System.out.println("fj.cookie=your_session_cookie_here");
|
||||
System.out.println("fj.url=https://share.feijipan.com/s/xxxxxxxxxx");
|
||||
System.out.println("fj.pwd=1234");
|
||||
System.out.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package cn.qaiu.parser.integration;
|
||||
|
||||
import cn.qaiu.entity.ShareLinkInfo;
|
||||
import cn.qaiu.parser.ParserCreate;
|
||||
import cn.qaiu.parser.IPanTool;
|
||||
|
||||
/**
|
||||
* 测试链接识别问题
|
||||
* 验证 https://pan.quark.cn/s/30e3c602ac09 是否被正确识别为夸克网盘
|
||||
*/
|
||||
public class LinkIdentifyTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("========================================");
|
||||
System.out.println(" 链接识别测试");
|
||||
System.out.println("========================================\n");
|
||||
|
||||
// 测试夸克链接
|
||||
testQkLink();
|
||||
|
||||
// 测试UC链接
|
||||
testUcLink();
|
||||
|
||||
System.out.println("\n========================================");
|
||||
System.out.println(" 测试完成");
|
||||
System.out.println("========================================");
|
||||
}
|
||||
|
||||
private static void testQkLink() {
|
||||
System.out.println("=== 测试夸克网盘链接识别 ===\n");
|
||||
|
||||
String url = "https://pan.quark.cn/s/30e3c602ac09";
|
||||
System.out.println("测试URL: " + url);
|
||||
|
||||
try {
|
||||
ParserCreate parserCreate = ParserCreate.fromShareUrl(url);
|
||||
ShareLinkInfo info = parserCreate.getShareLinkInfo();
|
||||
|
||||
System.out.println("识别结果:");
|
||||
System.out.println(" 网盘名称: " + info.getPanName());
|
||||
System.out.println(" 网盘类型: " + info.getType());
|
||||
System.out.println(" 分享KEY: " + info.getShareKey());
|
||||
System.out.println(" 标准URL: " + info.getStandardUrl());
|
||||
|
||||
if ("qk".equalsIgnoreCase(info.getType())) {
|
||||
System.out.println("\n✅ 链接正确识别为夸克网盘");
|
||||
} else {
|
||||
System.out.println("\n❌ 链接识别错误! 期望: qk, 实际: " + info.getType());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("\n❌ 识别失败: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
private static void testUcLink() {
|
||||
System.out.println("=== 测试UC网盘链接识别 ===\n");
|
||||
|
||||
String url = "https://drive.uc.cn/s/e623b6da278e4";
|
||||
System.out.println("测试URL: " + url);
|
||||
|
||||
try {
|
||||
ParserCreate parserCreate = ParserCreate.fromShareUrl(url);
|
||||
ShareLinkInfo info = parserCreate.getShareLinkInfo();
|
||||
|
||||
System.out.println("识别结果:");
|
||||
System.out.println(" 网盘名称: " + info.getPanName());
|
||||
System.out.println(" 网盘类型: " + info.getType());
|
||||
System.out.println(" 分享KEY: " + info.getShareKey());
|
||||
System.out.println(" 标准URL: " + info.getStandardUrl());
|
||||
|
||||
if ("uc".equalsIgnoreCase(info.getType())) {
|
||||
System.out.println("\n✅ 链接正确识别为UC网盘");
|
||||
} else {
|
||||
System.out.println("\n❌ 链接识别错误! 期望: uc, 实际: " + info.getType());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("\n❌ 识别失败: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
194
parser/src/test/java/cn/qaiu/parser/integration/README.md
Normal file
194
parser/src/test/java/cn/qaiu/parser/integration/README.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# 带认证的网盘解析集成测试
|
||||
|
||||
## 📋 概述
|
||||
|
||||
这个测试套件用于验证 UC、夸克和小飞机网盘的完整解析流程,包括认证、Cookie 处理和直链获取。
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 1. 准备配置文件
|
||||
|
||||
```bash
|
||||
cd parser/src/test/resources
|
||||
cp auth-test.properties.template auth-test.properties
|
||||
```
|
||||
|
||||
### 2. 填写认证信息
|
||||
|
||||
编辑 `auth-test.properties` 文件,填入真实的 Cookie 和分享链接。
|
||||
|
||||
**如何获取 Cookie:**
|
||||
|
||||
1. 在浏览器中登录对应网盘(夸克/UC)
|
||||
2. 打开开发者工具(F12)
|
||||
3. 切换到 Network 标签
|
||||
4. 刷新页面
|
||||
5. 找到任意请求,在请求头中复制完整的 Cookie
|
||||
|
||||
**夸克网盘 Cookie 示例:**
|
||||
```
|
||||
__pus=abc123; __kp=def456; __kps=ghi789; __ktd=jkl012; __uid=mno345; __puus=pqr678
|
||||
```
|
||||
|
||||
**UC 网盘 Cookie 示例:**
|
||||
```
|
||||
__pus=xyz123; __kp=uvw456; __kps=rst789; __ktd=opq012; __uid=lmn345; __puus=ijk678
|
||||
```
|
||||
|
||||
### 3. 运行测试
|
||||
|
||||
```bash
|
||||
cd parser
|
||||
mvn exec:java -Dexec.mainClass="cn.qaiu.parser.integration.AuthParseIntegrationTest" -Dexec.classpathScope=test -q
|
||||
```
|
||||
|
||||
或者使用编译后运行:
|
||||
|
||||
```bash
|
||||
mvn test-compile
|
||||
java -cp target/test-classes:target/classes:$(mvn dependency:build-classpath -q -Dmdep.outputFile=/dev/stdout) cn.qaiu.parser.integration.AuthParseIntegrationTest
|
||||
```
|
||||
|
||||
## 📝 配置文件格式
|
||||
|
||||
```properties
|
||||
# 夸克网盘(必须认证)
|
||||
qk.cookie=__pus=xxx; __kp=xxx; ...
|
||||
qk.url=https://pan.quark.cn/s/xxxxxxxxxx
|
||||
qk.pwd=
|
||||
|
||||
# UC 网盘(必须认证)
|
||||
uc.cookie=__pus=xxx; __kp=xxx; ...
|
||||
uc.url=https://fast.uc.cn/s/xxxxxxxxxx
|
||||
uc.pwd=
|
||||
|
||||
# 小飞机网盘(大文件需认证)
|
||||
fj.cookie=session_id=xxx
|
||||
fj.url=https://share.feijipan.com/s/xxxxxxxxxx
|
||||
fj.pwd=1234
|
||||
```
|
||||
|
||||
## 🧪 测试内容
|
||||
|
||||
### 1. 夸克网盘测试
|
||||
- ✅ Cookie 过滤和应用
|
||||
- ✅ __puus 自动刷新机制
|
||||
- ✅ 解析带认证的分享链接
|
||||
- ✅ 获取直链
|
||||
- ✅ 验证直链格式
|
||||
|
||||
### 2. UC 网盘测试
|
||||
- ✅ Cookie 过滤和应用
|
||||
- ✅ __puus 自动刷新机制
|
||||
- ✅ 解析带认证的分享链接
|
||||
- ✅ 获取直链
|
||||
- ✅ 验证直链格式
|
||||
|
||||
### 3. 小飞机网盘测试
|
||||
- ✅ 可选认证配置
|
||||
- ✅ 解析带密码的分享链接
|
||||
- ✅ 大文件认证处理
|
||||
- ✅ 获取直链
|
||||
- ✅ 验证直链格式
|
||||
|
||||
## 📊 测试输出示例
|
||||
|
||||
```
|
||||
========================================
|
||||
带认证的解析集成测试
|
||||
========================================
|
||||
|
||||
✓ 配置文件加载成功
|
||||
|
||||
=== 测试夸克网盘解析(带认证)===
|
||||
分享链接: https://pan.quark.cn/s/abc123def
|
||||
Cookie: __pus=abc1...xyz789
|
||||
|
||||
开始解析...
|
||||
|
||||
✅ 夸克网盘解析成功!
|
||||
耗时: 1234ms
|
||||
直链: https://download.quark.cn/file/xxx
|
||||
✓ 直链格式正确
|
||||
|
||||
=== 测试 UC 网盘解析(带认证)===
|
||||
分享链接: https://fast.uc.cn/s/def456ghi
|
||||
Cookie: __pus=def4...uvw012
|
||||
|
||||
开始解析...
|
||||
|
||||
✅ UC 网盘解析成功!
|
||||
耗时: 2345ms
|
||||
直链: https://download.uc.cn/file/xxx
|
||||
✓ 直链格式正确
|
||||
|
||||
========================================
|
||||
集成测试完成
|
||||
========================================
|
||||
```
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
1. **Cookie 安全性**
|
||||
- 不要将包含真实 Cookie 的配置文件提交到版本控制
|
||||
- `auth-test.properties` 已在 `.gitignore` 中
|
||||
- Cookie 包含敏感信息,请妥善保管
|
||||
|
||||
2. **Cookie 有效期**
|
||||
- Cookie 通常有效期为 1-7 天
|
||||
- 过期后需要重新获取
|
||||
- 如果解析失败,首先检查 Cookie 是否过期
|
||||
|
||||
3. **网盘限制**
|
||||
- 夸克和 UC 网盘**必须**提供 Cookie 才能解析
|
||||
- 小飞机网盘仅大文件(>100MB)需要 Cookie
|
||||
- 部分分享链接可能有下载次数限制
|
||||
|
||||
4. **测试环境**
|
||||
- 需要网络连接
|
||||
- 建议使用真实的大文件分享链接测试
|
||||
- 超时时间设置为 30 秒
|
||||
|
||||
## 🔍 故障排查
|
||||
|
||||
### 解析失败
|
||||
|
||||
1. **检查 Cookie 格式**
|
||||
- 确保包含所有必需字段:`__pus`, `__kp`, `__kps`, `__ktd`, `__uid`, `__puus`
|
||||
- 没有多余的空格或换行符
|
||||
|
||||
2. **检查分享链接**
|
||||
- 链接格式正确
|
||||
- 链接未过期
|
||||
- 分享密码正确(如果有)
|
||||
|
||||
3. **查看详细日志**
|
||||
- 运行时不加 `-q` 参数查看完整日志
|
||||
- 检查网络请求和响应
|
||||
|
||||
### Cookie 过期
|
||||
|
||||
- 重新登录网盘
|
||||
- 重新获取 Cookie
|
||||
- 更新配置文件
|
||||
|
||||
### 网络超时
|
||||
|
||||
- 检查网络连接
|
||||
- 可能是网盘服务器响应慢
|
||||
- 可以修改代码中的超时时间(默认30秒)
|
||||
|
||||
## 📚 相关文档
|
||||
|
||||
- [Cookie 工具类文档](../java/cn/qaiu/util/CookieUtils.java)
|
||||
- [夸克网盘解析器](../java/cn/qaiu/parser/impl/QkTool.java)
|
||||
- [UC 网盘解析器](../java/cn/qaiu/parser/impl/UcTool.java)
|
||||
- [小飞机网盘解析器](../java/cn/qaiu/parser/impl/FjTool.java)
|
||||
- [认证参数指南](../../doc/auth-param/AUTH_PARAM_GUIDE.md)
|
||||
|
||||
## 💡 提示
|
||||
|
||||
- 首次运行前确保已执行 `mvn compile` 编译项目
|
||||
- 如果未配置某个网盘,该网盘的测试会自动跳过
|
||||
- 测试结果包含解析耗时,可用于性能评估
|
||||
- Cookie 会自动过滤,只保留必需字段
|
||||
191
parser/src/test/java/cn/qaiu/parser/integration/TEST_RESULTS.md
Normal file
191
parser/src/test/java/cn/qaiu/parser/integration/TEST_RESULTS.md
Normal file
@@ -0,0 +1,191 @@
|
||||
# 认证解析集成测试结果
|
||||
|
||||
## 测试日期
|
||||
2026-02-05
|
||||
|
||||
## 测试环境
|
||||
- Java: 17+
|
||||
- Maven: 3.x
|
||||
- 系统: macOS
|
||||
|
||||
## 测试配置
|
||||
|
||||
### 小飞机网盘 ✅
|
||||
- **用户名**: 15764091073
|
||||
- **URL**: https://share.feijipan.com/s/ZWYoZ31c
|
||||
- **文件**: 资源.rar (1.13 GB)
|
||||
- **认证方式**: username/password
|
||||
|
||||
### UC网盘 ⏸️
|
||||
- **Cookie**: 已配置(长度 2.5KB)
|
||||
- **URL**: 未提供
|
||||
- **状态**: 等待分享链接
|
||||
|
||||
### 夸克网盘 ⏸️
|
||||
- **Cookie**: 未配置
|
||||
- **URL**: 未提供
|
||||
- **状态**: 等待认证信息和分享链接
|
||||
|
||||
## 测试结果
|
||||
|
||||
### ✅ 小飞机网盘 - 成功
|
||||
```
|
||||
=== 测试小飞机网盘解析(带认证)===
|
||||
分享链接: https://share.feijipan.com/s/ZWYoZ31c
|
||||
用户名: 15764091073
|
||||
密码: ******
|
||||
|
||||
开始解析...
|
||||
2026-02-05 17:06:10.188 INFO 登录成功 token: f2d2186d...
|
||||
2026-02-05 17:06:10.374 INFO 验证成功 userId: 4481273
|
||||
|
||||
✅ 小飞机网盘解析成功!
|
||||
耗时: 1690ms
|
||||
直链: https://dl-app.feejii.com/storage/files/2025/11/02/0/13000720/176208936345513.gz?t=6984648a&rlimit=20&us=Em7C0Gdaaz&sign=b954cdef169f2d883e1dfe4a6c9762fa&download_name=%E8%B5%84%E6%BA%90.rar&p=4481273-4481273-24620369057
|
||||
✓ 直链格式正确
|
||||
```
|
||||
|
||||
**验证项**:
|
||||
- ✅ 用户名密码认证成功
|
||||
- ✅ 登录和token获取正常
|
||||
- ✅ 用户ID验证通过
|
||||
- ✅ 直链生成成功
|
||||
- ✅ 解析耗时合理(1.69秒)
|
||||
- ✅ 大文件(1GB+)解析正常
|
||||
|
||||
### ⏸️ UC网盘 - 等待测试
|
||||
**原因**: 缺少分享链接URL
|
||||
|
||||
**已准备**:
|
||||
- ✅ Cookie配置完整(包含所有必需字段)
|
||||
- ✅ CookieUtils工具已验证(7/7测试通过)
|
||||
- ✅ UcTool认证逻辑已验证
|
||||
- ✅ __puus自动刷新机制已实现
|
||||
|
||||
**下一步**: 提供UC网盘分享链接后即可测试
|
||||
|
||||
### ⏸️ 夸克网盘 - 等待测试
|
||||
**原因**: 缺少Cookie和分享链接URL
|
||||
|
||||
**已准备**:
|
||||
- ✅ CookieUtils工具已验证(7/7测试通过)
|
||||
- ✅ QkTool认证逻辑已验证
|
||||
- ✅ __puus自动刷新机制已实现
|
||||
|
||||
**下一步**: 提供夸克网盘Cookie和分享链接后即可测试
|
||||
|
||||
## 前端增强 ✅
|
||||
|
||||
### 新增功能:智能网盘类型检测和提示
|
||||
|
||||
**实现方式**:
|
||||
1. 解析前调用 `/v2/linkInfo` API 获取网盘类型
|
||||
2. 根据网盘类型给出相应提示
|
||||
|
||||
**提示规则**:
|
||||
|
||||
| 网盘类型 | 代码 | 提示内容 | 持续时间 |
|
||||
|---------|------|---------|---------|
|
||||
| 夸克网盘 | `qk` | "无法在网页端直接下载,请点击'生成下载命令'按钮,使用命令行工具下载" | 5秒 |
|
||||
| UC网盘 | `uc` | "无法在网页端直接下载,请点击'生成下载命令'按钮,使用命令行工具下载" | 5秒 |
|
||||
| 小飞机 | `fj` | "的大文件解析需要配置认证信息,请在'配置认证'中添加" | 4秒 |
|
||||
| 蓝奏云 | `lz` | "的大文件解析需要配置认证信息,请在'配置认证'中添加" | 4秒 |
|
||||
| 蓝奏优享 | `iz` | "的大文件解析需要配置认证信息,请在'配置认证'中添加" | 4秒 |
|
||||
| 联想乐云 | `le` | "的大文件解析需要配置认证信息,请在'配置认证'中添加" | 4秒 |
|
||||
|
||||
**修改文件**:
|
||||
- [Home.vue](../../../../../../../web-front/src/views/Home.vue) - parseFile() 方法
|
||||
|
||||
## 工具验证状态
|
||||
|
||||
### ✅ CookieUtils - 全部通过
|
||||
- 测试文件: [CookieUtilsManualTest.java](../utils/CookieUtilsManualTest.java)
|
||||
- 测试通过: 7/7
|
||||
- 验证项:
|
||||
- ✅ Cookie字段过滤
|
||||
- ✅ getValue提取
|
||||
- ✅ updateCookie更新
|
||||
- ✅ containsKey检查
|
||||
- ✅ 空值处理
|
||||
- ✅ 复杂场景
|
||||
- ✅ UC/QK所有必需字段
|
||||
|
||||
### ✅ UC/QK Tool - 全部通过
|
||||
- 测试文件: [UcQkToolValidationTest.java](../impl/UcQkToolValidationTest.java)
|
||||
- 测试通过: 4/4
|
||||
- 验证项:
|
||||
- ✅ QK带认证实例化
|
||||
- ✅ UC带认证实例化
|
||||
- ✅ QK无认证实例化
|
||||
- ✅ UC无认证实例化
|
||||
|
||||
## 技术细节
|
||||
|
||||
### Cookie字段要求
|
||||
UC和夸克都需要以下6个Cookie字段:
|
||||
- `__pus` - 用户会话标识
|
||||
- `__kp` - 密钥标识
|
||||
- `__kps` - 密钥会话
|
||||
- `__ktd` - 密钥令牌数据
|
||||
- `__uid` - 用户ID
|
||||
- `__puus` - 持久用户会话(55分钟自动刷新)
|
||||
|
||||
### 自动刷新机制
|
||||
- **刷新间隔**: 55分钟
|
||||
- **有效期**: 1小时
|
||||
- **安全边际**: 5分钟
|
||||
- **实现**: Vertx定时器自动执行
|
||||
|
||||
### 认证参数加密
|
||||
- **算法**: AES/ECB/PKCS5Padding
|
||||
- **密钥**: "nfd_auth_key2026"
|
||||
- **编码**: Base64 → URL编码
|
||||
- **参数名**: `auth`
|
||||
|
||||
## 下次测试准备
|
||||
|
||||
### UC网盘
|
||||
需要提供:
|
||||
- ✅ Cookie(已有)
|
||||
- ⏸️ 分享链接URL(待提供)
|
||||
- ⏸️ 提取码(可选)
|
||||
|
||||
### 夸克网盘
|
||||
需要提供:
|
||||
- ⏸️ Cookie(待提供)
|
||||
- ⏸️ 分享链接URL(待提供)
|
||||
- ⏸️ 提取码(可选)
|
||||
|
||||
## 运行命令
|
||||
|
||||
```bash
|
||||
# 方法1: 使用便捷脚本
|
||||
cd parser
|
||||
bash src/test/java/cn/qaiu/parser/integration/run-test.sh
|
||||
|
||||
# 方法2: Maven直接运行
|
||||
cd parser
|
||||
mvn exec:java \
|
||||
-Dexec.mainClass="cn.qaiu.parser.integration.AuthParseIntegrationTest" \
|
||||
-Dexec.classpathScope=test \
|
||||
-q
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
✅ **已完成**:
|
||||
1. 小飞机网盘认证解析测试 - 成功
|
||||
2. CookieUtils工具验证 - 全部通过
|
||||
3. UC/QK Tool实例化验证 - 全部通过
|
||||
4. 集成测试框架 - 就绪
|
||||
5. 前端类型检测和提示 - 已实现
|
||||
|
||||
⏸️ **待测试**:
|
||||
1. UC网盘完整解析流程(等待分享链接)
|
||||
2. 夸克网盘完整解析流程(等待Cookie和链接)
|
||||
|
||||
📋 **建议**:
|
||||
1. 获取UC网盘的真实分享链接进行测试
|
||||
2. 获取夸克网盘的Cookie和分享链接进行测试
|
||||
3. 测试不同文件大小的解析性能
|
||||
4. 验证前端UI提示是否正确显示
|
||||
76
parser/src/test/java/cn/qaiu/parser/integration/run-test.sh
Executable file
76
parser/src/test/java/cn/qaiu/parser/integration/run-test.sh
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 带认证的网盘解析集成测试运行脚本
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
|
||||
CONFIG_FILE="$SCRIPT_DIR/../resources/auth-test.properties"
|
||||
TEMPLATE_FILE="$SCRIPT_DIR/../resources/auth-test.properties.template"
|
||||
|
||||
echo "========================================="
|
||||
echo " 网盘解析集成测试运行器"
|
||||
echo "========================================="
|
||||
echo
|
||||
|
||||
# 检查配置文件
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
echo "❌ 配置文件不存在: $CONFIG_FILE"
|
||||
echo
|
||||
echo "请先创建配置文件:"
|
||||
echo " cp $TEMPLATE_FILE $CONFIG_FILE"
|
||||
echo
|
||||
echo "然后编辑配置文件,填入真实的 Cookie 和分享链接"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ 找到配置文件: $CONFIG_FILE"
|
||||
echo
|
||||
|
||||
# 检查配置文件是否为空或只有模板
|
||||
if ! grep -q "qk.url=http" "$CONFIG_FILE" && \
|
||||
! grep -q "uc.url=http" "$CONFIG_FILE" && \
|
||||
! grep -q "fj.url=http" "$CONFIG_FILE"; then
|
||||
echo "⚠️ 配置文件似乎未填写实际数据"
|
||||
echo
|
||||
read -p "是否继续?(y/N) " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "已取消"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# 切换到 parser 目录
|
||||
cd "$PROJECT_ROOT/parser" || exit 1
|
||||
|
||||
echo "开始编译..."
|
||||
mvn compile -q -DskipTests
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ 编译失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ 编译成功"
|
||||
echo
|
||||
echo "开始运行测试..."
|
||||
echo "========================================="
|
||||
echo
|
||||
|
||||
# 运行测试
|
||||
mvn exec:java \
|
||||
-Dexec.mainClass="cn.qaiu.parser.integration.AuthParseIntegrationTest" \
|
||||
-Dexec.classpathScope=test \
|
||||
-q
|
||||
|
||||
TEST_RESULT=$?
|
||||
|
||||
echo
|
||||
echo "========================================="
|
||||
if [ $TEST_RESULT -eq 0 ]; then
|
||||
echo "✓ 测试运行完成"
|
||||
else
|
||||
echo "❌ 测试运行失败(退出码: $TEST_RESULT)"
|
||||
fi
|
||||
echo "========================================="
|
||||
|
||||
exit $TEST_RESULT
|
||||
67
parser/src/test/resources/auth-test.properties.template
Normal file
67
parser/src/test/resources/auth-test.properties.template
Normal file
@@ -0,0 +1,67 @@
|
||||
# ========================================
|
||||
# 网盘认证信息配置文件
|
||||
# ========================================
|
||||
#
|
||||
# 使用说明:
|
||||
# 1. 将此文件重命名为 auth-test.properties
|
||||
# 2. 填入真实的 Cookie 和分享链接
|
||||
# 3. 运行测试: mvn exec:java -Dexec.mainClass="cn.qaiu.parser.integration.AuthParseIntegrationTest" -Dexec.classpathScope=test
|
||||
#
|
||||
# 如何获取 Cookie:
|
||||
# 1. 在浏览器中登录对应网盘
|
||||
# 2. 打开开发者工具(F12)
|
||||
# 3. 切换到 Network 标签
|
||||
# 4. 刷新页面
|
||||
# 5. 找到任意请求,在请求头中复制完整的 Cookie
|
||||
#
|
||||
|
||||
# ========================================
|
||||
# 夸克网盘配置(必须认证)
|
||||
# ========================================
|
||||
# 分享链接示例: https://pan.quark.cn/s/abc123def
|
||||
qk.url=
|
||||
|
||||
# Cookie 必需字段: __pus, __kp, __kps, __ktd, __uid, __puus
|
||||
# 完整示例: __pus=abc123; __kp=def456; __kps=ghi789; __ktd=jkl012; __uid=mno345; __puus=pqr678
|
||||
qk.cookie=
|
||||
|
||||
# 分享密码(如果有)
|
||||
qk.pwd=
|
||||
|
||||
|
||||
# ========================================
|
||||
# UC 网盘配置(必须认证)
|
||||
# ========================================
|
||||
# 分享链接示例: https://fast.uc.cn/s/abc123def
|
||||
uc.url=
|
||||
|
||||
# Cookie 必需字段: __pus, __kp, __kps, __ktd, __uid, __puus
|
||||
# 完整示例: __pus=abc123; __kp=def456; __kps=ghi789; __ktd=jkl012; __uid=mno345; __puus=pqr678
|
||||
uc.cookie=
|
||||
|
||||
# 分享密码(如果有)
|
||||
uc.pwd=
|
||||
|
||||
|
||||
# ========================================
|
||||
# 小飞机网盘配置(大文件需认证)
|
||||
# ========================================
|
||||
# 分享链接示例: https://share.feijipan.com/s/abc123def
|
||||
fj.url=
|
||||
|
||||
# Cookie(大文件 >100MB 时需要)
|
||||
# 完整示例: session_id=abc123; auth_token=def456
|
||||
fj.cookie=
|
||||
|
||||
# 分享密码
|
||||
fj.pwd=
|
||||
|
||||
|
||||
# ========================================
|
||||
# 注意事项
|
||||
# ========================================
|
||||
# 1. Cookie 中的特殊字符无需转义
|
||||
# 2. 不要添加多余的空格
|
||||
# 3. 密码可以为空
|
||||
# 4. 未配置的网盘会自动跳过测试
|
||||
# 5. Cookie 有效期通常为 1-7 天,过期需要重新获取
|
||||
Reference in New Issue
Block a user