fix: support 123pan redirected share links

This commit is contained in:
q
2026-07-06 08:49:29 +08:00
parent 275f6b9e6d
commit 24bf98bca9
5 changed files with 498 additions and 418 deletions
@@ -208,7 +208,7 @@ public enum PanDomainTemplate {
123795.com
*/
YE("123网盘",
compile("https://www\\.(" +
compile("https://(?:[a-zA-Z\\d-]+\\.)*(" +
"123254\\.com|" +
"123957\\.com|" +
"123295\\.com|" +
@@ -232,7 +232,7 @@ public enum PanDomainTemplate {
"123635\\.com|" +
"123242\\.com|" +
"123795\\.com" +
")/s/(?<KEY>[a-zA-Z0-9_-]+)(?:\\.html)?"),
")/(?:(?:s|123pan)/|(?:[^/?#]+/)+)?(?<KEY>[a-zA-Z0-9]+-[a-zA-Z0-9]+|[a-zA-Z0-9_-]+)(?:\\.html)?(?:\\?.*)?"),
"https://www.123pan.com/s/{shareKey}",
Ye2Tool.class),
// https://www.ecpan.cn/web/#/yunpanProxy?path=%2F%23%2Fdrive%2Foutside&data={code}&isShare=1
@@ -0,0 +1,53 @@
package cn.qaiu.parser;
import org.apache.commons.lang3.StringUtils;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Parser token cache keyed by parser type and account identity.
*/
public final class TokenCache {
private static final Map<String, String> TOKENS = new ConcurrentHashMap<>();
private static final Map<String, Long> EXPIRES = new ConcurrentHashMap<>();
private TokenCache() {
}
public static String key(String type, String accountId) {
return type + ":" + (StringUtils.isBlank(accountId) ? "_default" : accountId);
}
public static void putToken(String key, String token) {
if (StringUtils.isBlank(key) || StringUtils.isBlank(token)) {
return;
}
TOKENS.put(key, token);
}
public static String getToken(String key) {
if (StringUtils.isBlank(key)) {
return null;
}
if (isExpired(key)) {
TOKENS.remove(key);
EXPIRES.remove(key);
return null;
}
return TOKENS.get(key);
}
public static void putExpire(String key, long expireTimeMillis) {
if (StringUtils.isBlank(key)) {
return;
}
EXPIRES.put(key, expireTimeMillis);
}
public static boolean isExpired(String key) {
Long expireTimeMillis = EXPIRES.get(key);
return expireTimeMillis != null && System.currentTimeMillis() > expireTimeMillis;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,84 @@
package cn.qaiu.util;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.Map;
/**
* 123分享链接子域工具:将分享 key 的前半段解码为数字 uid。
*/
public final class YeShareHostUtil {
private static final String CODE62 = "Tvd3hHA9QEkom14xpfaBJIMwgFYGPXn2sWCNORDr80KuUSl7bZcetizL5q6yVj";
private static final long MAX_SAFE_INTEGER = 9007199254740991L;
private static final Map<Character, Integer> DECODE_MAP = new HashMap<>();
static {
for (int i = 0; i < CODE62.length(); i++) {
DECODE_MAP.put(CODE62.charAt(i), i);
}
}
private YeShareHostUtil() {
}
public static String getNumericSubdomainIdByShareKey(String shareKey) {
String normalized = normalizeShareKey(shareKey);
if (StringUtils.isBlank(normalized)) {
return "";
}
int split = normalized.indexOf('-');
if (split <= 0) {
return "";
}
String encodedUid = normalized.substring(0, split);
Long uid = decodeBase62LittleEndian(encodedUid);
return uid == null ? "" : String.valueOf(uid);
}
public static String normalizeShareKey(String shareKey) {
if (StringUtils.isBlank(shareKey)) {
return "";
}
String key = shareKey.trim();
int queryIndex = key.indexOf('?');
if (queryIndex >= 0) {
key = key.substring(0, queryIndex);
}
int slashIndex = key.lastIndexOf('/');
if (slashIndex >= 0 && slashIndex < key.length() - 1) {
key = key.substring(slashIndex + 1);
}
if (key.endsWith(".html")) {
key = key.substring(0, key.length() - 5);
}
return key;
}
private static Long decodeBase62LittleEndian(String value) {
if (StringUtils.isBlank(value)) {
return null;
}
long result = 0L;
for (int i = 0; i < value.length(); i++) {
Integer digit = DECODE_MAP.get(value.charAt(i));
if (digit == null) {
return null;
}
double weighted = digit * Math.pow(62, i);
if (!Double.isFinite(weighted)) {
return null;
}
long next = result + (long) weighted;
if (next <= 0 || next > MAX_SAFE_INTEGER) {
return null;
}
result = next;
}
if (result <= 0) {
return null;
}
return result;
}
}
@@ -1,6 +1,7 @@
package cn.qaiu.parser;
import cn.qaiu.entity.ShareLinkInfo;
import cn.qaiu.util.YeShareHostUtil;
import org.junit.Test;
import java.util.Arrays;
@@ -157,6 +158,26 @@ public class PanDomainTemplateTest {
assertEquals("somekey", m5.group("KEY"));
}
@Test
public void testYeRedirectPatternAndUidDecode() {
Pattern yePattern = PanDomainTemplate.YE.getPattern();
Matcher oldUrl = yePattern.matcher("https://www.123pan.com/s/lN7UVv-pbYJ");
assertTrue("YE should match old 123pan share URL", oldUrl.find());
assertEquals("lN7UVv-pbYJ", oldUrl.group("KEY"));
Matcher redirectedUrl = yePattern.matcher("https://1813382308.mshare.123pan.cn/123pan/lN7UVv-pbYJ");
assertTrue("YE should match redirected mshare URL", redirectedUrl.find());
assertEquals("lN7UVv-pbYJ", redirectedUrl.group("KEY"));
Matcher htmlUrl = yePattern.matcher("https://www.123278.com/s/lN7UVv-pbYJ.html?pwd=abcd");
assertTrue("YE should match html URL with query", htmlUrl.find());
assertEquals("lN7UVv-pbYJ", htmlUrl.group("KEY"));
assertEquals("1813382308", YeShareHostUtil.getNumericSubdomainIdByShareKey("lN7UVv-pbYJ"));
assertEquals("lN7UVv-pbYJ", YeShareHostUtil.normalizeShareKey("https://1813382308.mshare.123pan.cn/123pan/lN7UVv-pbYJ?pwd=abcd"));
}
@Test
public void testLePatternFix() {
Pattern lePattern = PanDomainTemplate.LE.getPattern();