1. 缓存优化

This commit is contained in:
qaiu
2024-09-18 13:24:33 +08:00
parent a0fe702c10
commit 59d2fb3010
24 changed files with 370 additions and 263 deletions

View File

@@ -203,9 +203,9 @@ bash service-install.sh
## 0.1.8 开发计划 ## 0.1.8 开发计划
- Docker部署 - Docker部署
- 联想乐云解析 - 联想乐云解析
- 直链缓存 - 直链缓存
- 日志优化 - 日志优化
**技术栈:** **技术栈:**

View File

@@ -66,7 +66,7 @@ public class ShareLinkInfo {
// 建造者类 // 建造者类
public static class Builder { public static class Builder {
private String shareKey; // 分享键 private String shareKey; // 分享键
private String type; // 分享类型 private String type; // 分享类型 (网盘模板枚举的小写)
private String sharePassword = ""; // 分享密码(如果存在) private String sharePassword = ""; // 分享密码(如果存在)
private String shareUrl; // 原始分享链接 private String shareUrl; // 原始分享链接
private String standardUrl; // 规范化的标准链接 private String standardUrl; // 规范化的标准链接

View File

@@ -4,28 +4,4 @@ import io.vertx.core.Future;
public interface IPanTool { public interface IPanTool {
Future<String> parse(); Future<String> parse();
// 基于枚举PanDomainTemplate匹配分享链接类型
static IPanTool typeMatching(String type, String key, String pwd) {
try {
return PanDomainTemplate
.fromShortName(type)
.generateShareLink(key)
.setShareLinkInfoPwd(pwd)
.createTool();
} catch (Exception e) {
throw new UnsupportedOperationException("未知分享类型", e);
}
}
static IPanTool shareURLPrefixMatching(String url, String pwd) {
try {
return PanDomainTemplate
.fromShareUrl(url)
.setShareLinkInfoPwd(pwd)
.createTool();
} catch (Exception e) {
throw new UnsupportedOperationException("未知分享类型", e);
}
}
} }

View File

@@ -1,23 +1,15 @@
package cn.qaiu.parser; package cn.qaiu.parser;
import cn.qaiu.entity.ShareLinkInfo;
import cn.qaiu.parser.impl.*; import cn.qaiu.parser.impl.*;
import org.apache.commons.lang3.StringUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* 枚举类 PanDomainTemplate 定义了不同网盘服务的模板信息,包括: * 枚举类 PanDomainTemplate 定义了不同网盘服务的模板信息,包括:
* <ul> * <ul>
* <li>displayName: 网盘服务的显示名称,用于用户界面展示。</li> * <li>displayName: 网盘服务的显示名称,用于用户界面展示。</li>
* <li>shortName: 网盘服务的简称用于内部逻辑处理例如API路径。</li>
* <li>regexPattern: 用于匹配和解析分享链接的正则表达式。</li> * <li>regexPattern: 用于匹配和解析分享链接的正则表达式。</li>
* <li>standardUrlTemplate: 网盘服务的标准URL模板用于规范化分享链接。</li> * <li>standardUrlTemplate: 网盘服务的标准URL模板用于规范化分享链接。</li>
* <li>toolClass: 网盘解析工具实现类。</li> * <li>toolClass: 网盘解析工具实现类。</li>
* </ul> * </ul>
* 该类提供方法来解析和规范化不同来源的分享链接,确保它们可以转换为统一的标准链接格式。
* 通过这种方式,应用程序可以更容易地处理和识别不同网盘服务的分享链接.
* *
* @author <a href="https://qaiu.top">QAIU</a> * @author <a href="https://qaiu.top">QAIU</a>
* at 2023/6/13 4:26 * at 2023/6/13 4:26
@@ -26,7 +18,6 @@ public enum PanDomainTemplate {
// 网盘定义 // 网盘定义
LZ("蓝奏云", LZ("蓝奏云",
"lz",
"https://([a-z]+)?\\.?lanzou[a-z]\\.com/(.+/)?(.+)", "https://([a-z]+)?\\.?lanzou[a-z]\\.com/(.+/)?(.+)",
"https://lanzoux.com/{shareKey}", "https://lanzoux.com/{shareKey}",
LzTool.class), LzTool.class),
@@ -34,64 +25,54 @@ public enum PanDomainTemplate {
// https://www.feijix.com/s/ // https://www.feijix.com/s/
// https://share.feijipan.com/s/ // https://share.feijipan.com/s/
FJ("小飞机网盘", FJ("小飞机网盘",
"fj",
"https://(share\\.feijipan\\.com|www\\.feijix\\.com)/s/(.+)", "https://(share\\.feijipan\\.com|www\\.feijix\\.com)/s/(.+)",
"https://www.feijix.com/s/{shareKey}", "https://www.feijix.com/s/{shareKey}",
FjTool.class), FjTool.class),
// https://lecloud.lenovo.com/share/ // https://lecloud.lenovo.com/share/
LE("联想乐云", LE("联想乐云",
"le",
"https://lecloud?\\.lenovo\\.com/share/(.+)", "https://lecloud?\\.lenovo\\.com/share/(.+)",
"https://lecloud.lenovo.com/share/{shareKey}", "https://lecloud.lenovo.com/share/{shareKey}",
LeTool.class), LeTool.class),
// https://v2.fangcloud.com/s/ // https://v2.fangcloud.com/s/
FC("亿方云", FC("亿方云",
"fc",
"https://v2\\.fangcloud\\.(com|cn)/(s|sharing)/([^/]+)", "https://v2\\.fangcloud\\.(com|cn)/(s|sharing)/([^/]+)",
"https://v2.fangcloud.com/s/{shareKey}", "https://v2.fangcloud.com/s/{shareKey}",
FcTool.class), FcTool.class),
// https://www.ilanzou.com/s/ // https://www.ilanzou.com/s/
IZ("蓝奏云优享", IZ("蓝奏云优享",
"iz",
"https://www\\.ilanzou\\.com/s/(.+)", "https://www\\.ilanzou\\.com/s/(.+)",
"https://www.ilanzou.com/s/{shareKey}", "https://www.ilanzou.com/s/{shareKey}",
IzTool.class), IzTool.class),
// https://wx.mail.qq.com/ftn/download? // https://wx.mail.qq.com/ftn/download?
QQ("QQ邮箱中转站", QQ("QQ邮箱中转站",
"qq",
"https://i?wx\\.mail\\.qq\\.com/ftn/download\\?(.+)", "https://i?wx\\.mail\\.qq\\.com/ftn/download\\?(.+)",
"https://iwx.mail.qq.com/ftn/download/{shareKey}", "https://iwx.mail.qq.com/ftn/download/{shareKey}",
QQTool.class), QQTool.class),
// https://f.ws59.cn/f/或者https://www.wenshushu.cn/f/ // https://f.ws59.cn/f/或者https://www.wenshushu.cn/f/
WS("文叔叔", WS("文叔叔",
"ws",
"https://(f\\.ws59\\.cn|www\\.wenshushu\\.cn)/f/(.+)", "https://(f\\.ws59\\.cn|www\\.wenshushu\\.cn)/f/(.+)",
"https://f.ws59.cn/f/{shareKey}", "https://f.ws59.cn/f/{shareKey}",
WsTool.class), WsTool.class),
// https://www.123pan.com/s/ // https://www.123pan.com/s/
YE("123网盘", YE("123网盘",
"ye",
"https://www\\.123pan\\.com/s/(.+)\\.html", "https://www\\.123pan\\.com/s/(.+)\\.html",
"https://www.123pan.com/s/{shareKey}.html", "https://www.123pan.com/s/{shareKey}.html",
YeTool.class), YeTool.class),
// https://www.ecpan.cn/web/#/yunpanProxy?path=%2F%23%2Fdrive%2Foutside&data={code}&isShare=1 // https://www.ecpan.cn/web/#/yunpanProxy?path=%2F%23%2Fdrive%2Foutside&data={code}&isShare=1
EC("移动云空间", EC("移动云空间",
"ec",
"https://www\\.ecpan\\.cn/web(/%23|/#)?/yunpanProxy\\?path=.*&data=" + "https://www\\.ecpan\\.cn/web(/%23|/#)?/yunpanProxy\\?path=.*&data=" +
"([^&]+)&isShare=1", "([^&]+)&isShare=1",
"https://www.ecpan.cn/web/#/yunpanProxy?path=%2F%23%2Fdrive%2Foutside&data={shareKey}&isShare=1", "https://www.ecpan.cn/web/#/yunpanProxy?path=%2F%23%2Fdrive%2Foutside&data={shareKey}&isShare=1",
EcTool.class), EcTool.class),
// https://cowtransfer.com/s/ // https://cowtransfer.com/s/
COW("奶牛快传", COW("奶牛快传",
"cow",
"https://(.*)cowtransfer\\.com/s/(.+)", "https://(.*)cowtransfer\\.com/s/(.+)",
"https://cowtransfer.com/s/{shareKey}", "https://cowtransfer.com/s/{shareKey}",
CowTool.class), CowTool.class),
// https://pan.huang1111.cn/s/ // https://pan.huang1111.cn/s/
CE("huang1111", CE("huang1111",
"ce",
"https://pan\\.huang1111\\.cn/s/(.+)", "https://pan\\.huang1111\\.cn/s/(.+)",
"https://pan.huang1111.cn/s/{shareKey}", "https://pan.huang1111.cn/s/{shareKey}",
CeTool.class); CeTool.class);
@@ -100,79 +81,25 @@ public enum PanDomainTemplate {
// 网盘的显示名称,用于用户界面显示 // 网盘的显示名称,用于用户界面显示
private final String displayName; private final String displayName;
// 网盘的简短名称用于内部逻辑处理如REST API路径
private final String shortName;
// 用于匹配和解析分享链接的正则表达式 // 用于匹配和解析分享链接的正则表达式
private final String regexPattern; private final String regexPattern;
// 网盘的标准链接模板,不含占位符,用于规范化分享链接 // 网盘的标准链接模板,不含占位符,用于规范化分享链接
private final String standardUrlTemplate; private final String standardUrlTemplate;
private final ShareLinkInfo shareLinkInfo;
// 指向IPanTool实现类 // 指向解析工具IPanTool实现类
private final Class<? extends IPanTool> toolClass; private final Class<? extends IPanTool> toolClass;
PanDomainTemplate(String displayName, String shortName, String regexPattern, PanDomainTemplate(String displayName, String regexPattern, String standardUrlTemplate,
String standardUrlTemplate, Class<? extends IPanTool> toolClass) { Class<? extends IPanTool> toolClass) {
this.displayName = displayName; this.displayName = displayName;
this.shortName = shortName;
this.regexPattern = regexPattern; this.regexPattern = regexPattern;
this.standardUrlTemplate = standardUrlTemplate; this.standardUrlTemplate = standardUrlTemplate;
this.toolClass = toolClass; this.toolClass = toolClass;
this.shareLinkInfo = ShareLinkInfo.newBuilder().type(shortName).build();
} }
// 解析并规范化分享链接
synchronized public PanDomainTemplate normalizeShareLink() {
if (shareLinkInfo == null) {
throw new IllegalArgumentException("ShareLinkInfo not init");
}
// 匹配并提取shareKey
String shareUrl = shareLinkInfo.getShareUrl();
if (StringUtils.isEmpty(shareUrl)) {
throw new IllegalArgumentException("ShareLinkInfo shareUrl is empty");
}
Pattern pattern = Pattern.compile(regexPattern);
Matcher matcher = pattern.matcher(shareUrl);
if (matcher.find()) {
String shareKey = matcher.group(matcher.groupCount());
// 返回规范化的标准链接
String standardUrl = standardUrlTemplate.replace("{shareKey}", shareKey);
shareLinkInfo.setShareUrl(shareUrl);
shareLinkInfo.setShareKey(shareKey);
shareLinkInfo.setStandardUrl(standardUrl);
return this;
}
throw new IllegalArgumentException("Invalid share URL for " + displayName);
}
public IPanTool createTool() {
if (shareLinkInfo == null || StringUtils.isEmpty(shareLinkInfo.getType())) {
throw new IllegalArgumentException("ShareLinkInfo not init or type is empty");
}
if (StringUtils.isEmpty(shareLinkInfo.getShareKey())) {
this.normalizeShareLink();
}
try {
return toolClass
.getDeclaredConstructor(ShareLinkInfo.class)
.newInstance(shareLinkInfo);
} catch (Exception e) {
throw new RuntimeException("无法创建工具实例: " + toolClass.getName(), e);
}
}
// 生成分享链接的方法
synchronized public PanDomainTemplate generateShareLink(String shareKey) {
shareLinkInfo.setShareKey(shareKey);
shareLinkInfo.setStandardUrl(standardUrlTemplate.replace("{shareKey}", shareKey));
return this;
}
public String getDisplayName() { public String getDisplayName() {
return this.displayName; return displayName;
} }
public String getRegexPattern() { public String getRegexPattern() {
@@ -183,43 +110,7 @@ public enum PanDomainTemplate {
return standardUrlTemplate; return standardUrlTemplate;
} }
public Class<? extends IPanTool> getToolClass() {
public ShareLinkInfo getShareLinkInfo() { return toolClass;
return shareLinkInfo;
}
synchronized public PanDomainTemplate setShareLinkInfoPwd(String pwd) {
shareLinkInfo.setSharePassword(pwd);
return this;
}
synchronized public PanDomainTemplate setShareLinkInfoUrl(String pwd) {
shareLinkInfo.setSharePassword(pwd);
return this;
}
// 根据分享链接获取PanDomainTemplate实例
synchronized public static PanDomainTemplate fromShareUrl(String shareUrl) {
for (PanDomainTemplate template : values()) {
if (shareUrl.matches(template.regexPattern)) {
template.getShareLinkInfo().setShareUrl(shareUrl);
return template.normalizeShareLink();
}
}
throw new IllegalArgumentException("Unsupported share URL");
}
// 根据shortName获取枚举实例
public static PanDomainTemplate fromShortName(String shortName) {
try {
return Enum.valueOf(PanDomainTemplate.class, shortName.toUpperCase());
} catch (IllegalArgumentException ignore) {
// 如果没有找到对应的枚举实例,抛出异常
throw new IllegalArgumentException("No enum constant for short name: " + shortName);
}
}
public String getShortName() {
return shortName;
} }
} }

View File

@@ -0,0 +1,113 @@
package cn.qaiu.parser;
import cn.qaiu.entity.ShareLinkInfo;
import org.apache.commons.lang3.StringUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 该类提供方法来解析和规范化不同来源的分享链接,确保它们可以转换为统一的标准链接格式。
* 通过这种方式,应用程序可以更容易地处理和识别不同网盘服务的分享链接。
*
* @author <a href="https://qaiu.top">QAIU</a>
* @date 2024/9/15 14:10
*/
public class ParserCreate {
private final PanDomainTemplate panDomainTemplate;
private final ShareLinkInfo shareLinkInfo;
public ParserCreate(PanDomainTemplate panDomainTemplate, ShareLinkInfo shareLinkInfo) {
this.panDomainTemplate = panDomainTemplate;
this.shareLinkInfo = shareLinkInfo;
}
// 解析并规范化分享链接
public ParserCreate normalizeShareLink() {
if (shareLinkInfo == null) {
throw new IllegalArgumentException("ShareLinkInfo not init");
}
// 匹配并提取shareKey
String shareUrl = shareLinkInfo.getShareUrl();
if (StringUtils.isEmpty(shareUrl)) {
throw new IllegalArgumentException("ShareLinkInfo shareUrl is empty");
}
Pattern pattern = Pattern.compile(this.panDomainTemplate.getRegexPattern());
Matcher matcher = pattern.matcher(shareUrl);
if (matcher.find()) {
String shareKey = matcher.group(matcher.groupCount());
// 返回规范化的标准链接
String standardUrl = getStandardUrlTemplate().replace("{shareKey}", shareKey);
shareLinkInfo.setShareUrl(shareUrl);
shareLinkInfo.setShareKey(shareKey);
shareLinkInfo.setStandardUrl(standardUrl);
return this;
}
throw new IllegalArgumentException("Invalid share URL for " + this.panDomainTemplate.getDisplayName());
}
public IPanTool createTool() {
if (shareLinkInfo == null || StringUtils.isEmpty(shareLinkInfo.getType())) {
throw new IllegalArgumentException("ShareLinkInfo not init or type is empty");
}
if (StringUtils.isEmpty(shareLinkInfo.getShareKey())) {
this.normalizeShareLink();
}
try {
return this.panDomainTemplate.getToolClass()
.getDeclaredConstructor(ShareLinkInfo.class)
.newInstance(shareLinkInfo);
} catch (Exception e) {
throw new RuntimeException("无法创建工具实例: " + panDomainTemplate.getToolClass().getName(), e);
}
}
// set share key
public ParserCreate shareKey(String shareKey) {
shareLinkInfo.setShareKey(shareKey);
shareLinkInfo.setStandardUrl(panDomainTemplate.getStandardUrlTemplate().replace("{shareKey}", shareKey));
return this;
}
public String getStandardUrlTemplate() {
return this.panDomainTemplate.getStandardUrlTemplate();
}
public ShareLinkInfo getShareLinkInfo() {
return shareLinkInfo;
}
public ParserCreate setShareLinkInfoPwd(String pwd) {
shareLinkInfo.setSharePassword(pwd);
return this;
}
// 根据分享链接获取PanDomainTemplate实例
public synchronized static ParserCreate fromShareUrl(String shareUrl) {
for (PanDomainTemplate panDomainTemplate : PanDomainTemplate.values()) {
if (shareUrl.matches(panDomainTemplate.getRegexPattern())) {
ShareLinkInfo shareLinkInfo = ShareLinkInfo.newBuilder()
.type(panDomainTemplate.name().toLowerCase())
.shareUrl(shareUrl).build();
ParserCreate parserCreate = new ParserCreate(panDomainTemplate, shareLinkInfo);
return parserCreate.normalizeShareLink();
}
}
throw new IllegalArgumentException("Unsupported share URL");
}
// 根据type获取枚举实例
public synchronized static ParserCreate fromType(String type) {
try {
PanDomainTemplate panDomainTemplate = Enum.valueOf(PanDomainTemplate.class, type.toUpperCase());
ShareLinkInfo shareLinkInfo = ShareLinkInfo.newBuilder()
.type(type.toLowerCase()).build();
return new ParserCreate(panDomainTemplate, shareLinkInfo);
} catch (IllegalArgumentException ignore) {
// 如果没有找到对应的枚举实例,抛出异常
throw new IllegalArgumentException("No enum constant for type name: " + type);
}
}
}

View File

@@ -19,15 +19,15 @@ public class PanDomainTemplateTest {
// 准备测试数据 // 准备测试数据
String testShareUrl = "https://test.lanzoux.com/s/someShareKey"; String testShareUrl = "https://test.lanzoux.com/s/someShareKey";
PanDomainTemplate template = PanDomainTemplate.fromShareUrl(testShareUrl); // 假设使用LZ网盘模板 ParserCreate parserCreate = ParserCreate.fromShareUrl(testShareUrl); // 假设使用LZ网盘模板
// 调用normalizeShareLink方法 // 调用normalizeShareLink方法
ShareLinkInfo result = template.getShareLinkInfo(); ShareLinkInfo result = parserCreate.getShareLinkInfo();
System.out.println(result); System.out.println(result);
// 断言结果是否符合预期 // 断言结果是否符合预期
assertNotNull("Result should not be null", result); assertNotNull("Result should not be null", result);
assertEquals("Share key should match", "someShareKey", result.getShareKey()); assertEquals("Share key should match", "someShareKey", result.getShareKey());
assertEquals("Standard URL should be generated correctly", template.getStandardUrlTemplate().replace("{shareKey}", "someShareKey"), result.getStandardUrl()); assertEquals("Standard URL should be generated correctly", parserCreate.getStandardUrlTemplate().replace("{shareKey}", "someShareKey"), result.getStandardUrl());
// 可以添加更多的断言来验证其他字段 // 可以添加更多的断言来验证其他字段
} }
@@ -38,25 +38,25 @@ public class PanDomainTemplateTest {
String cowUrl = "https://cowtransfer.com/s/9a644fe3e3a748"; String cowUrl = "https://cowtransfer.com/s/9a644fe3e3a748";
String ceUrl = "https://pan.huang1111.cn/s/g31PcQ"; String ceUrl = "https://pan.huang1111.cn/s/g31PcQ";
String wsUrl = "https://f.ws59.cn/f/f25625rv6p6"; String wsUrl = "https://f.ws59.cn/f/f25625rv6p6";
PanDomainTemplate.fromShareUrl(wsUrl).createTool() // ParserCreate.fromShareUrl(wsUrl).createTool()
.parse().onSuccess(System.out::println); // .parse().onSuccess(System.out::println);
PanDomainTemplate.fromShareUrl(lzUrl).createTool() // ParserCreate.fromShareUrl(lzUrl).createTool()
.parse().onSuccess(System.out::println); // .parse().onSuccess(System.out::println);
PanDomainTemplate.fromShareUrl(cowUrl).createTool() // ParserCreate.fromShareUrl(cowUrl).createTool()
.parse().onSuccess(System.out::println); // .parse().onSuccess(System.out::println);
PanDomainTemplate.fromShareUrl(lzUrl).createTool() ParserCreate.fromShareUrl(lzUrl).createTool()
.parse().onSuccess(System.out::println); .parse().onSuccess(System.out::println);
// PanDomainTemplate.fromShortName("lz").generateShareLink("ihLkw1gezutg") // ParserCreate.fromType("lz").shareKey("ihLkw1gezutg")
// .createTool().parse().onSuccess(System.out::println); // .createTool().parse().onSuccess(System.out::println);
// PanDomainTemplate.LZ.generateShareLink("ihLkw1gezutg") // ParserCreate.LZ.shareKey("ihLkw1gezutg")
// .createTool().parse().onSuccess(System.out::println); // .createTool().parse().onSuccess(System.out::println);
// 调用fromShareUrl方法 // 调用fromShareUrl方法
// PanDomainTemplate resultTemplate = PanDomainTemplate.fromShareUrl(testShareUrl); // PanDomainTemplate resultTemplate = ParserCreate.fromShareUrl(testShareUrl);
// System.out.println(resultTemplate.normalizeShareLink(testShareUrl)); // System.out.println(resultTemplate.normalizeShareLink(testShareUrl));
// System.out.println(resultTemplate.generateShareLink("xxx")); // System.out.println(resultTemplate.shareKey("xxx"));
// System.out.println(resultTemplate.createTool("xxx",null).parse() // System.out.println(resultTemplate.createTool("xxx",null).parse()
// .onSuccess(System.out::println)); // .onSuccess(System.out::println));
// System.out.println(resultTemplate.getDisplayName()); // System.out.println(resultTemplate.getDisplayName());
@@ -65,7 +65,7 @@ public class PanDomainTemplateTest {
// //
// // 断言结果是否符合预期 // // 断言结果是否符合预期
// assertNotNull("Result should not be null", resultTemplate); // assertNotNull("Result should not be null", resultTemplate);
// assertEquals("Should return the correct template", PanDomainTemplate.LZ, resultTemplate); // assertEquals("Should return the correct template", ParserCreate.LZ, resultTemplate);
// // 可以添加更多的断言来验证正则表达式匹配逻辑 // // 可以添加更多的断言来验证正则表达式匹配逻辑
// new Scanner(System.in).nextLine(); // new Scanner(System.in).nextLine();
TimeUnit.SECONDS.sleep(5); TimeUnit.SECONDS.sleep(5);

View File

@@ -11,7 +11,8 @@
content="Netdisk fast download 网盘直链解析工具"> content="Netdisk fast download 网盘直链解析工具">
<script charset="UTF-8" id="LA_COLLECT" src="//sdk.51.la/js-sdk-pro.min.js"></script> <script charset="UTF-8" id="LA_COLLECT" src="//sdk.51.la/js-sdk-pro.min.js"></script>
<script>LA.init({id:"K8zkCkZMgFA6ShZK",ck:"K8zkCkZMgFA6ShZK"})</script> <script>LA.init({id:"K8zkCkZMgFA6ShZK",ck:"K8zkCkZMgFA6ShZK"})</script>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9851170484804006"
crossorigin="anonymous"></script>
<style> <style>
.page-loading-wrap { .page-loading-wrap {
padding: 120px; padding: 120px;

View File

@@ -11,15 +11,12 @@
<div class="typo"> <div class="typo">
<p><strong>项目GitHub </strong><a href="https://github.com/qaiu/netdisk-fast-download" target="_blank" <p><strong>项目GitHub </strong><a href="https://github.com/qaiu/netdisk-fast-download" target="_blank"
rel="nofollow"><u>netdisk-fast-download</u></a></p> rel="nofollow"><u>netdisk-fast-download</u></a></p>
<p><strong>当前页面修改自开源项目</strong><a href="https://github.com/HurryBy/CloudDiskAnalysis" <p><strong>目前支持 </strong>蓝奏云/蓝奏云优享/小飞机盘/123云盘/奶牛快传/移动云云空间/亿方云/文叔叔/QQ邮箱文件中转站</p>
target="_blank"
rel="nofollow"><u>CloudDiskAnalysis</u></a></p>
<p><strong>目前支持 </strong>已支持蓝奏云/奶牛快传/移动云云空间/UC网盘(暂时失效)/小飞机盘/亿方云/123云盘</p>
<p> <p>
<el-button><strong @click="getInfo">刷新API调用统计</strong></el-button> <el-button><strong @click="getInfo">刷新API调用统计</strong></el-button>
</p> </p>
<p>节点1: 成功:{{ node1Info.success }},失败:{{ node1Info.fail }},总数:{{ node1Info.total }}</p> <p>节点1: 回源请求数:{{ node1Info.parserTotal }}, 缓存请求数:{{ node1Info.cacheTotal }}, 总数:{{ node1Info.total }}</p>
<p>节点2: 成功:{{ node2Info.success }},失败:{{ node2Info.fail }},总数:{{ node2Info.total }}</p> <!-- <p>节点2: 成功:{{ node2Info.success }},失败:{{ node2Info.fail }},总数:{{ node2Info.total }}</p>-->
</div> </div>
<hr> <hr>
<div class="main" v-loading="isLoading"> <div class="main" v-loading="isLoading">
@@ -153,6 +150,7 @@ export default {
} else { } else {
this.$message.error(response.data.msg) this.$message.error(response.data.msg)
} }
this.getInfo()
}, },
error => { error => {
this.isLoading = false this.isLoading = false
@@ -174,12 +172,12 @@ export default {
this.node1Info = response.data.data this.node1Info = response.data.data
} }
}) })
axios.get('/n2/statisticsInfo').then( // axios.get('/n2/statisticsInfo').then(
response => { // response => {
if (response.data.success) { // if (response.data.success) {
this.node2Info = response.data.data // this.node2Info = response.data.data
} // }
}) // })
} }
}, },
mounted() { mounted() {

View File

@@ -29,9 +29,9 @@ public class CacheConfigLoader {
} }
public static Integer getDuration(PanDomainTemplate pdt) { public static Integer getDuration(PanDomainTemplate pdt) {
return CONFIGS.get(pdt.getShortName()); return CONFIGS.get(pdt.name().toLowerCase());
} }
public static Integer getDuration(String shortName) { public static Integer getDuration(String type) {
return CONFIGS.get(shortName); return CONFIGS.get(type.toLowerCase());
} }
} }

View File

@@ -6,6 +6,7 @@ import io.vertx.core.Future;
import io.vertx.core.Promise; import io.vertx.core.Promise;
import io.vertx.core.json.JsonObject; import io.vertx.core.json.JsonObject;
import io.vertx.jdbcclient.JDBCPool; import io.vertx.jdbcclient.JDBCPool;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.templates.SqlTemplate; import io.vertx.sqlclient.templates.SqlTemplate;
import java.util.HashMap; import java.util.HashMap;
@@ -16,7 +17,7 @@ public class CacheManager {
public Future<CacheLinkInfo> get(String cacheKey) { public Future<CacheLinkInfo> get(String cacheKey) {
String sql = "SELECT direct_link as directLink, expiration FROM cache_link_info WHERE share_key = #{share_key}"; String sql = "SELECT share_key as shareKey, direct_link as directLink, expiration FROM cache_link_info WHERE share_key = #{share_key}";
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("share_key", cacheKey); params.put("share_key", cacheKey);
Promise<CacheLinkInfo> promise = Promise.promise(); Promise<CacheLinkInfo> promise = Promise.promise();
@@ -29,7 +30,7 @@ public class CacheManager {
cacheHit = rows.iterator().next(); cacheHit = rows.iterator().next();
cacheHit.setCacheHit(true); cacheHit.setCacheHit(true);
} else { } else {
cacheHit = new CacheLinkInfo(JsonObject.of("cacheHit", false)); cacheHit = new CacheLinkInfo(JsonObject.of("cacheHit", false, "shareKey", cacheKey));
} }
promise.complete(cacheHit); promise.complete(cacheHit);
}).onFailure(Throwable::printStackTrace); }).onFailure(Throwable::printStackTrace);
@@ -49,4 +50,80 @@ public class CacheManager {
.execute(cacheLinkInfo) .execute(cacheLinkInfo)
.mapEmpty(); .mapEmpty();
} }
// 统计网盘厂商API解析次数
public Future<Integer> updateTotalByCached(String shareKey) {
Promise<Integer> promise = Promise.promise();
String sql = """
MERGE INTO `api_statistics_info` (`pan_type`, `share_key`, `cache_hit_total`, `update_ts`)
KEY (`share_key`)
VALUES (#{panType}, #{shareKey}, #{total}, #{ts})
""";
getShareKeyTotal(shareKey, "cache_hit_total").onSuccess(total -> {
Integer newTotal = (total == null ? 0 : total) + 1;
SqlTemplate.forUpdate(jdbcPool, sql)
.execute(new HashMap<>() {{
put("panType", getShareType(shareKey));
put("shareKey", shareKey);
put("total", newTotal);
put("ts", System.currentTimeMillis());
}})
.onSuccess(res -> promise.complete(res.rowCount()))
.onFailure(Throwable::printStackTrace);
});
return promise.future();
}
private String getShareType(String fullShareKey) {
// 将type和shareKey组合成一个字符串作为缓存key
return fullShareKey.split(":")[0];
}
// 统计网盘厂商API解析次数
public Future<Integer> updateTotalByParser(String shareKey) {
Promise<Integer> promise = Promise.promise();
String sql = """
MERGE INTO `api_statistics_info` (`pan_type`, `share_key`, `api_parser_total`, `update_ts`)
KEY (`share_key`)
VALUES (#{panType}, #{shareKey}, #{total}, #{ts})
""";
getShareKeyTotal(shareKey, "api_parser_total").onSuccess(total -> {
Integer newTotal = (total == null ? 0 : total) + 1;
SqlTemplate.forUpdate(jdbcPool, sql)
.execute(new HashMap<>() {{
put("panType", getShareType(shareKey));
put("shareKey", shareKey);
put("total", newTotal);
put("ts", System.currentTimeMillis());
}})
.onSuccess(res -> promise.complete(res.rowCount()))
.onFailure(Throwable::printStackTrace);
});
return promise.future();
}
public Future<Integer> getShareKeyTotal(String shareKey, String name) {
String sql = """
select `share_key`, sum({total_name}) sum_num
from `api_statistics_info`
group by `share_key` having `share_key` = #{shareKey};
""".replace("{total_name}", name);
Promise<Integer> promise = Promise.promise();
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("shareKey", shareKey);
SqlTemplate.forQuery(jdbcPool, sql)
.mapTo(Row::toJson)
.execute(paramMap)
.onSuccess(res -> {
Integer total = res.iterator().hasNext() ?
res.iterator().next().getInteger("sum_num") : null;
promise.complete(total);
});
return promise.future();
}
} }

View File

@@ -20,7 +20,7 @@ public class DefaultInterceptor implements BeforeInterceptor {
@Override @Override
public void handle(RoutingContext ctx) { public void handle(RoutingContext ctx) {
System.out.println("进入前置拦截器1->" + ctx.request().path()); // System.out.println("进入前置拦截器1->" + ctx.request().path());
doNext(ctx); doNext(ctx);
} }

View File

@@ -4,7 +4,6 @@ import cn.qaiu.db.pool.JDBCPoolInit;
import cn.qaiu.lz.common.model.ParserLogInfo; import cn.qaiu.lz.common.model.ParserLogInfo;
import cn.qaiu.vx.core.annotaions.HandleSortFilter; import cn.qaiu.vx.core.annotaions.HandleSortFilter;
import cn.qaiu.vx.core.interceptor.AfterInterceptor; import cn.qaiu.vx.core.interceptor.AfterInterceptor;
import cn.qaiu.vx.core.model.JsonResult;
import cn.qaiu.vx.core.util.CommonUtil; import cn.qaiu.vx.core.util.CommonUtil;
import cn.qaiu.vx.core.util.SharedDataUtil; import cn.qaiu.vx.core.util.SharedDataUtil;
import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonArray;
@@ -36,21 +35,8 @@ public class LogStatistics implements AfterInterceptor {
ParserLogInfo parserLogInfo = new ParserLogInfo(); ParserLogInfo parserLogInfo = new ParserLogInfo();
parserLogInfo.setPath(ctx.request().uri()); parserLogInfo.setPath(ctx.request().uri());
if (responseData == null) { if (responseData.containsKey("code") && responseData.getInteger("code") == 500) {
String location = ctx.response().headers().get("location"); log.error("code 500: {} {}", ctx.request().path(), responseData.getString("msg"));
if (location != null) {
parserLogInfo.setCode(200);
parserLogInfo.setData(location);
} else {
log.error("location不存在且responseData为空, path={}", ctx.request().path());
}
insert(parserLogInfo);
} else if (responseData.containsKey("code")) {
JsonResult<?> result = JsonResult.toJsonResult(responseData);
parserLogInfo.setCode(result.getCode());
parserLogInfo.setData(result.getCode() == 500 ? result.getMsg() : result.getData().toString());
insert(parserLogInfo);
} else { } else {
log.error("未知json日志: {}, path: {}", responseData.encode(), ctx.request().path()); log.error("未知json日志: {}, path: {}", responseData.encode(), ctx.request().path());
} }

View File

@@ -14,6 +14,8 @@ public class ParserLogInfo {
String id = SnowflakeIdWorker.getStringId(); String id = SnowflakeIdWorker.getStringId();
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS", timezone = "GMT+8")
Date logTime = new Date(); Date logTime = new Date();
@Length(varcharSize = 4096)
String path; String path;
Integer code; Integer code;

View File

@@ -1,8 +1,8 @@
package cn.qaiu.lz.web.http; package cn.qaiu.lz.web.http;
import cn.qaiu.lz.common.util.URLParamUtil; import cn.qaiu.lz.common.util.URLParamUtil;
import cn.qaiu.lz.web.model.CacheLinkInfo;
import cn.qaiu.lz.web.service.CacheService; import cn.qaiu.lz.web.service.CacheService;
import cn.qaiu.parser.PanDomainTemplate;
import cn.qaiu.vx.core.annotaions.RouteHandler; import cn.qaiu.vx.core.annotaions.RouteHandler;
import cn.qaiu.vx.core.annotaions.RouteMapping; import cn.qaiu.vx.core.annotaions.RouteMapping;
import cn.qaiu.vx.core.enums.RouteMethod; import cn.qaiu.vx.core.enums.RouteMethod;
@@ -31,8 +31,7 @@ public class ServerApi {
Promise<Void> promise = Promise.promise(); Promise<Void> promise = Promise.promise();
String url = URLParamUtil.parserParams(request); String url = URLParamUtil.parserParams(request);
PanDomainTemplate panDomainTemplate = PanDomainTemplate.fromShareUrl(url).setShareLinkInfoPwd(pwd); cacheService.getCachedByShareUrlAndPwd(url, pwd)
cacheService.getAndSaveCachedShareLink(panDomainTemplate)
.onSuccess(res -> ResponseUtil.redirect( .onSuccess(res -> ResponseUtil.redirect(
response.putHeader("nfd-cache-hit", res.getCacheHit().toString()) response.putHeader("nfd-cache-hit", res.getCacheHit().toString())
.putHeader("nfd-cache-expires", res.getExpires()), .putHeader("nfd-cache-expires", res.getExpires()),
@@ -42,39 +41,32 @@ public class ServerApi {
} }
@RouteMapping(value = "/json/parser", method = RouteMethod.GET, order = 3) @RouteMapping(value = "/json/parser", method = RouteMethod.GET, order = 3)
public Future<String> parseJson(HttpServerRequest request, String pwd) { public Future<CacheLinkInfo> parseJson(HttpServerRequest request, String pwd) {
String url = URLParamUtil.parserParams(request); String url = URLParamUtil.parserParams(request);
return PanDomainTemplate.fromShareUrl(url).setShareLinkInfoPwd(pwd).createTool().parse(); return cacheService.getCachedByShareUrlAndPwd(url, pwd);
} }
@RouteMapping(value = "/json/:type/:key", method = RouteMethod.GET, order = 2) @RouteMapping(value = "/json/:type/:key", method = RouteMethod.GET, order = 2)
public Future<String> parseKeyJson(String type, String key) { public Future<CacheLinkInfo> parseKeyJson(String type, String key) {
String code = ""; String pwd = "";
if (key.contains("@")) { if (key.contains("@")) {
String[] keys = key.split("@"); String[] keys = key.split("@");
key = keys[0]; key = keys[0];
code = keys[1]; pwd = keys[1];
} }
return PanDomainTemplate.fromShortName(type) return cacheService.getCachedByShareKeyAndPwd(type, key, pwd);
.generateShareLink(key).setShareLinkInfoPwd(code).createTool().parse();
} }
@RouteMapping(value = "/:type/:key", method = RouteMethod.GET, order = 1) @RouteMapping(value = "/:type/:key", method = RouteMethod.GET, order = 1)
public Future<Void> parseKey(HttpServerResponse response, String type, String key) { public Future<Void> parseKey(HttpServerResponse response, String type, String key) {
Promise<Void> promise = Promise.promise(); Promise<Void> promise = Promise.promise();
String code = ""; String pwd = "";
if (key.contains("@")) { if (key.contains("@")) {
String[] keys = key.split("@"); String[] keys = key.split("@");
key = keys[0]; key = keys[0];
code = keys[1]; pwd = keys[1];
} }
cacheService.getCachedByShareKeyAndPwd(type, key, pwd)
PanDomainTemplate panDomainTemplate = PanDomainTemplate
.fromShortName(type)
.generateShareLink(key)
.setShareLinkInfoPwd(code);
cacheService.getAndSaveCachedShareLink(panDomainTemplate)
.onSuccess(res -> ResponseUtil.redirect( .onSuccess(res -> ResponseUtil.redirect(
response.putHeader("nfd-cache-hit", res.getCacheHit().toString()) response.putHeader("nfd-cache-hit", res.getCacheHit().toString())
.putHeader("nfd-cache-expires", res.getExpires()), .putHeader("nfd-cache-expires", res.getExpires()),

View File

@@ -0,0 +1,68 @@
package cn.qaiu.lz.web.model;
import cn.qaiu.db.ddl.Length;
import cn.qaiu.db.ddl.Table;
import cn.qaiu.lz.common.ToJson;
import io.vertx.codegen.annotations.DataObject;
import io.vertx.core.json.JsonObject;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author <a href="https://qaiu.top">QAIU</a>
* @date 2024/9/11 16:06
*/
@Table(value = "api_statistics_info", keyFields = "share_key")
@Data
@DataObject
@NoArgsConstructor
public class ApiStatisticsInfo implements ToJson {
/**
* pan type 单独拿出来便于统计.
*/
@Length(varcharSize = 4)
private String panType;
/**
* 分享key type:key
*/
@Length(varcharSize = 4096)
private String shareKey;
/**
* 命中缓存次数
*/
private Integer cacheHitTotal;
/**
* api解析次数
*/
private Integer apiParserTotal;
/**
* 更新时间戳
*/
private Long updateTs;
// 使用 JsonObject 构造
public ApiStatisticsInfo(JsonObject json) {
if (json.containsKey("panType")) {
this.setPanType(json.getString("panType"));
}
if (json.containsKey("shareKey")) {
this.setShareKey(json.getString("shareKey"));
}
if (json.containsKey("cacheHitTotal")) {
this.setCacheHitTotal(json.getInteger("cacheHitTotal"));
}
if (json.containsKey("apiParserTotal")) {
this.setApiParserTotal(json.getInteger("apiParserTotal"));
}
if (json.containsKey("updateTs")) {
this.setUpdateTs(json.getLong("updateTs"));
}
}
}

View File

@@ -20,7 +20,7 @@ import lombok.NoArgsConstructor;
public class CacheLinkInfo implements ToJson { public class CacheLinkInfo implements ToJson {
/** /**
* 缓存key: type@ShareKey; e.g. lz@xxxx * 缓存key: type:ShareKey; e.g. lz:xxxx
*/ */
@Length(varcharSize = 4096) @Length(varcharSize = 4096)
private String shareKey; private String shareKey;
@@ -51,6 +51,20 @@ public class CacheLinkInfo implements ToJson {
// 使用 JsonObject 构造 // 使用 JsonObject 构造
public CacheLinkInfo(JsonObject json) { public CacheLinkInfo(JsonObject json) {
CacheLinkInfoConverter.fromJson(json, this); if (json.containsKey("shareKey")) {
this.setShareKey(json.getString("shareKey"));
}
if (json.containsKey("directLink")) {
this.setDirectLink(json.getString("directLink"));
}
if (json.containsKey("expires")) {
this.setExpires(json.getString("expires"));
}
if (json.containsKey("expiration")) {
this.setExpiration(json.getLong("expiration"));
}
this.setCacheHit(json.getBoolean("cacheHit", false));
} }
} }

View File

@@ -1,23 +0,0 @@
package cn.qaiu.lz.web.model;
import io.vertx.core.json.JsonObject;
// CacheLinkInfoConverter.java
public class CacheLinkInfoConverter {
public static void fromJson(JsonObject json, CacheLinkInfo obj) {
if (json.containsKey("shareKey")) {
obj.setShareKey(json.getString("shareKey"));
}
if (json.containsKey("directLink")) {
obj.setDirectLink(json.getString("directLink"));
}
if (json.containsKey("expires")) {
obj.setExpires(json.getString("expires"));
}
if (json.containsKey("expiration")) {
obj.setExpiration(json.getLong("expiration"));
}
obj.setCacheHit(json.getBoolean("cacheHit", false));
}
}

View File

@@ -10,14 +10,14 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor @NoArgsConstructor
@DataObject @DataObject
public class StatisticsInfo implements ToJson { public class StatisticsInfo implements ToJson {
Integer fail; Integer parserTotal;
Integer success; Integer cacheTotal;
Integer total; Integer total;
public StatisticsInfo(JsonObject jsonObject) { public StatisticsInfo(JsonObject jsonObject) {
this.fail = jsonObject.getInteger("fail"); this.parserTotal = jsonObject.getInteger("parserTotal");
this.success = jsonObject.getInteger("success"); this.cacheTotal = jsonObject.getInteger("cacheTotal");
this.total = jsonObject.getInteger("total"); this.total = jsonObject.getInteger("total");
} }
} }

View File

@@ -1,7 +1,6 @@
package cn.qaiu.lz.web.service; package cn.qaiu.lz.web.service;
import cn.qaiu.lz.web.model.CacheLinkInfo; import cn.qaiu.lz.web.model.CacheLinkInfo;
import cn.qaiu.parser.PanDomainTemplate;
import cn.qaiu.vx.core.base.BaseAsyncService; import cn.qaiu.vx.core.base.BaseAsyncService;
import io.vertx.codegen.annotations.ProxyGen; import io.vertx.codegen.annotations.ProxyGen;
import io.vertx.core.Future; import io.vertx.core.Future;
@@ -13,5 +12,7 @@ import io.vertx.core.Future;
@ProxyGen @ProxyGen
public interface CacheService extends BaseAsyncService { public interface CacheService extends BaseAsyncService {
Future<CacheLinkInfo> getAndSaveCachedShareLink(PanDomainTemplate shareLinkInfo); Future<CacheLinkInfo> getCachedByShareKeyAndPwd(String type, String shareKey, String pwd);
Future<CacheLinkInfo> getCachedByShareUrlAndPwd(String shareUrl, String pwd);
} }

View File

@@ -5,7 +5,7 @@ import cn.qaiu.lz.common.cache.CacheConfigLoader;
import cn.qaiu.lz.common.cache.CacheManager; import cn.qaiu.lz.common.cache.CacheManager;
import cn.qaiu.lz.web.model.CacheLinkInfo; import cn.qaiu.lz.web.model.CacheLinkInfo;
import cn.qaiu.lz.web.service.CacheService; import cn.qaiu.lz.web.service.CacheService;
import cn.qaiu.parser.PanDomainTemplate; import cn.qaiu.parser.ParserCreate;
import cn.qaiu.vx.core.annotaions.Service; import cn.qaiu.vx.core.annotaions.Service;
import io.vertx.core.Future; import io.vertx.core.Future;
import io.vertx.core.Promise; import io.vertx.core.Promise;
@@ -19,21 +19,22 @@ public class CacheServiceImpl implements CacheService {
private final CacheManager cacheManager = new CacheManager(); private final CacheManager cacheManager = new CacheManager();
@Override private Future<CacheLinkInfo> getAndSaveCachedShareLink(ParserCreate parserCreate) {
public Future<CacheLinkInfo> getAndSaveCachedShareLink(PanDomainTemplate template) {
Promise<CacheLinkInfo> promise = Promise.promise(); Promise<CacheLinkInfo> promise = Promise.promise();
// 构建组合的缓存key // 构建组合的缓存key
ShareLinkInfo shareLinkInfo = template.getShareLinkInfo(); ShareLinkInfo shareLinkInfo = parserCreate.getShareLinkInfo();
String cacheKey = generateCacheKey(shareLinkInfo.getType(), shareLinkInfo.getShareKey()); String cacheKey = generateCacheKey(shareLinkInfo.getType(), shareLinkInfo.getShareKey());
// 尝试从缓存中获取 // 尝试从缓存中获取
cacheManager.get(cacheKey).onSuccess(result -> { cacheManager.get(cacheKey).onSuccess(result -> {
// 判断是否已过期 // 判断是否已过期
// 未命中或者过期 // 未命中或者过期
if (!result.getCacheHit() || result.getExpiration() < System.currentTimeMillis()) { if (!result.getCacheHit() || result.getExpiration() < System.currentTimeMillis()) {
template.createTool().parse().onSuccess(redirectUrl -> { // parse
result.setCacheHit(false);
result.setExpiration(0L);
parserCreate.createTool().parse().onSuccess(redirectUrl -> {
long expires = System.currentTimeMillis() + long expires = System.currentTimeMillis() +
CacheConfigLoader.getDuration(shareLinkInfo.getType()) * 60 * 1000; CacheConfigLoader.getDuration(shareLinkInfo.getType()) * 60 * 1000L;
result.setDirectLink(redirectUrl); result.setDirectLink(redirectUrl);
// result.setExpires(generateDate(expires)); // result.setExpires(generateDate(expires));
promise.complete(result); promise.complete(result);
@@ -45,10 +46,12 @@ public class CacheServiceImpl implements CacheService {
"shareKey", cacheKey "shareKey", cacheKey
)); ));
cacheManager.cacheShareLink(cacheLinkInfo).onFailure(Throwable::printStackTrace); cacheManager.cacheShareLink(cacheLinkInfo).onFailure(Throwable::printStackTrace);
cacheManager.updateTotalByParser(cacheKey).onFailure(Throwable::printStackTrace);
}).onFailure(promise::fail); }).onFailure(promise::fail);
} else { } else {
result.setExpires(generateDate(result.getExpiration())); result.setExpires(generateDate(result.getExpiration()));
promise.complete(result); promise.complete(result);
cacheManager.updateTotalByCached(cacheKey).onFailure(Throwable::printStackTrace);
} }
}).onFailure(t -> promise.fail(t.fillInStackTrace())); }).onFailure(t -> promise.fail(t.fillInStackTrace()));
return promise.future(); return promise.future();
@@ -62,4 +65,16 @@ public class CacheServiceImpl implements CacheService {
private String generateDate(Long ts) { private String generateDate(Long ts) {
return DateFormatUtils.format(new Date(ts), "yyyy-MM-dd hh:mm:ss"); return DateFormatUtils.format(new Date(ts), "yyyy-MM-dd hh:mm:ss");
} }
@Override
public Future<CacheLinkInfo> getCachedByShareKeyAndPwd(String type, String shareKey, String pwd) {
ParserCreate parserCreate = ParserCreate.fromType(type).shareKey(shareKey).setShareLinkInfoPwd(pwd);
return getAndSaveCachedShareLink(parserCreate);
}
@Override
public Future<CacheLinkInfo> getCachedByShareUrlAndPwd(String shareUrl, String pwd) {
ParserCreate parserCreate = ParserCreate.fromShareUrl(shareUrl).setShareLinkInfoPwd(pwd);
return getAndSaveCachedShareLink(parserCreate);
}
} }

View File

@@ -48,10 +48,9 @@ public class DbServiceImpl implements DbService {
JDBCPool client = JDBCPoolInit.instance().getPool(); JDBCPool client = JDBCPoolInit.instance().getPool();
Promise<StatisticsInfo> promise = Promise.promise(); Promise<StatisticsInfo> promise = Promise.promise();
String sql = """ String sql = """
select COUNT(CASE "code" WHEN 500 THEN "code" END ) "fail", select sum(api_parser_total) parserTotal,sum("cache_hit_total") cacheTotal,
COUNT(CASE "code" WHEN 200 THEN "code" END ) "success", sum(api_parser_total) + sum("cache_hit_total") total
count(1) "total" from "api_statistics_info";
from "t_parser_log_info"
"""; """;
SqlTemplate.forQuery(client, sql).mapTo(StatisticsInfo.class).execute(new HashMap<>()).onSuccess(row -> { SqlTemplate.forQuery(client, sql).mapTo(StatisticsInfo.class).execute(new HashMap<>()).onSuccess(row -> {
StatisticsInfo info; StatisticsInfo info;

View File

@@ -54,7 +54,7 @@ cache:
iz: iz:
le: 2879 le: 2879
lz: lz:
qq: qq: 999999
ws: ws:
ye: ye:

View File

@@ -8,14 +8,14 @@ GET http://127.0.0.1:6400/json/parser?url=https://wwsd.lanzoue.com/iLany1e9bbbi
### 蓝奏云 ### 蓝奏云
# @no-redirect # @no-redirect
GET http://127.0.0.1:6400/lz/i6SqHmp1yfc GET http://127.0.0.1:6400/json/lz/i6SqHmp1yfc
### 蓝奏云https://acgtools.lanzoui.com/iUr7Qnu3sxc https://wwn.lanzouy.com/tp/ihLkw1gezutg https://wwn.lanzouy.com/ihLkw1gezutg ### 蓝奏云https://acgtools.lanzoui.com/iUr7Qnu3sxc https://wwn.lanzouy.com/tp/ihLkw1gezutg https://wwn.lanzouy.com/ihLkw1gezutg
# @no-redirect # @no-redirect
GET http://127.0.0.1:6400/lz/ihLkw1gezutg GET http://127.0.0.1:6400/lz/ihLkw1gezutg
### 蓝奏云 ### 蓝奏云
# @no-redirect # @no-redirect
GET http://127.0.0.1:6400/lz/icBp6qqj82b@QAIU GET http://127.0.0.1:6400/json/lz/icBp6qqj82b@QAIU
### 蓝奏云 ### 蓝奏云
GET http://127.0.0.1:6400/json/lz/ia2cntg GET http://127.0.0.1:6400/json/lz/ia2cntg
@@ -133,7 +133,7 @@ GET http://127.0.0.1:6400/le/2RkKbLP9BrppS9b43@ex2b
GET http://127.0.0.1:6400/json/le/2RkKbLP9BrppS9b43@ex2b GET http://127.0.0.1:6400/json/le/2RkKbLP9BrppS9b43@ex2b
### PASS 文叔叔 ### PASS 文叔叔
GET http://127.0.0.1:6400/json/parser?url=https://f.ws59.cn/f/f25625rv6p6 GET http://127.0.0.1:6400/parser?url=https://f.ws59.cn/f/f25625rv6p6
### ###
https://f.wss.cc/f/f25625rv6p6 https://f.wss.cc/f/f25625rv6p6
@@ -145,7 +145,7 @@ GET http://127.0.0.1:6400/parser?url=https://pan.huang1111.cn/s/g31PcQ&pwd=qaiu
### PASS QQ ### PASS QQ
# @no-redirect # @no-redirect
GET http://127.0.0.1:6400/parser?url=https://iwx.mail.qq.com/ftn/download?func=3&key=c79c5732038ad41cf5ef1e3261663537f2cf4133636635371d4c484657050c0e5d561d070252021a0a0552024e5257530b4e0157540256525e5751565a053b374014540057560c070b511e53130d21f0361c829bf15b3e4a6355fbada6dd10dfdd11a33263663537386330&code=8c02cf57&k=c79c5732038ad41cf5ef1e3261663537f2cf4133636635371d4c484657050c0e5d561d070252021a0a0552024e5257530b4e0157540256525e5751565a053b374014540057560c070b511e53130d21f0361c829bf15b3e4a6355fbada6dd10dfdd11a33263663537386330 GET http://127.0.0.1:6400/json/parser?url=https://iwx.mail.qq.com/ftn/download?func=3&key=qweqe&code=8c02cf57&k=asdad