mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2025-12-16 20:33:03 +00:00
Compare commits
21 Commits
0.1.8.bate
...
0.1.8.prox
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e424f7bf4 | ||
|
|
294e47deed | ||
|
|
dc42547b73 | ||
|
|
7ef7f0706b | ||
|
|
a59b98a7c9 | ||
|
|
088fee9a4d | ||
|
|
d8666acfe8 | ||
|
|
209e9c2866 | ||
|
|
6c3195dea4 | ||
|
|
7d774a7433 | ||
|
|
f1ec4433cf | ||
|
|
1f825db261 | ||
|
|
1019f24f1d | ||
|
|
f5c5b99579 | ||
|
|
e002d19f1b | ||
|
|
0d5c9651f0 | ||
|
|
53fc13b95c | ||
|
|
694c3b0ddc | ||
|
|
9b3d4577cc | ||
|
|
77783915dd | ||
|
|
b67ac21a79 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -39,3 +39,4 @@ gradlew.bat
|
||||
unused.txt
|
||||
/web-service/src/main/generated/
|
||||
/db
|
||||
/webroot/nfd-front/
|
||||
|
||||
@@ -7,10 +7,11 @@ main分支依赖JDK17, 提供了JDK11分支[main-jdk11](https://github.com/qaiu/
|
||||
[](https://github.com/qaiu/netdisk-fast-download/actions/workflows/maven.yml)
|
||||
[](https://www.oracle.com/cn/java/technologies/downloads/)
|
||||
[](https://vertx-china.github.io/)
|
||||
[](https://github.com/qaiu/netdisk-fast-download/releases/tag/0.1.6-releases)
|
||||
[](https://github.com/qaiu/netdisk-fast-download/releases/latest)
|
||||
|
||||
## 项目介绍
|
||||
网盘直链解析工具能把网盘分享下载链接转化为直链,已支持蓝奏云/蓝奏云优享/奶牛快传/移动云云空间/小飞机盘/亿方云/123云盘/Cloudreve等,支持加密分享。
|
||||
**20240929 1k Star留念,0.1.8版本json接口格式有调整,尤其依赖lz.qaiu.top做下载服务的朋友们记得修改, 参考json返回数据格式示例**
|
||||
|
||||
|
||||
*重要声明:本项目仅供学习参考;请不要将此项目用于任何商业用途,否则可能带来严重的后果。转发/分享该项目请注明来源*
|
||||
@@ -148,6 +149,7 @@ mvn package
|
||||
```
|
||||
打包好的文件位于 web-service/target/netdisk-fast-download-bin.zip
|
||||
## Linux服务部署
|
||||
### [宝塔安装参考](https://blog.qaiu.top/archives/netdisk-fast-download-bao-ta-an-zhuang-jiao-cheng)
|
||||
> 注意: netdisk-fast-download.service中的ExecStart的路径改为实际路径
|
||||
```shell
|
||||
cd ~
|
||||
@@ -201,7 +203,7 @@ Core模块集成Vert.x实现类似spring的注解式路由API
|
||||
|
||||
|
||||
## 支持该项目
|
||||
本项目长期维护如果觉得有帮助, 可以请作者喝杯咖啡, 感谢支持
|
||||
开源不易,用爱发电,本项目长期维护如果觉得有帮助, 可以请作者喝杯咖啡, 感谢支持
|
||||

|
||||
|
||||
[手机端支付宝打赏跳转链接](https://qr.alipay.com/fkx01882dnoxxtjenhlxt53)
|
||||
|
||||
@@ -21,7 +21,7 @@ public class JDBCPoolInit {
|
||||
JsonObject dbConfig;
|
||||
Vertx vertx = VertxHolder.getVertxInstance();
|
||||
String url;
|
||||
private JDBCType type;
|
||||
private final JDBCType type;
|
||||
|
||||
private static JDBCPoolInit instance;
|
||||
|
||||
@@ -64,22 +64,17 @@ public class JDBCPoolInit {
|
||||
* init h2db<br>
|
||||
* 这个方法只允许调用一次
|
||||
*/
|
||||
public void initPool() {
|
||||
synchronized public void initPool() {
|
||||
if (pool != null) {
|
||||
LOGGER.error("pool 重复初始化");
|
||||
return;
|
||||
}
|
||||
|
||||
// 初始化数据库连接
|
||||
vertx.createSharedWorkerExecutor("sql-pool-init")
|
||||
.executeBlocking(() -> {
|
||||
// 初始化连接池
|
||||
pool = JDBCPool.pool(vertx, dbConfig);
|
||||
CreateTable.createTable(pool, type);
|
||||
return "数据库连接初始化: URL=" + url;
|
||||
})
|
||||
.onSuccess(LOGGER::info)
|
||||
.onFailure(Throwable::printStackTrace);
|
||||
// 初始化连接池
|
||||
pool = JDBCPool.pool(vertx, dbConfig);
|
||||
CreateTable.createTable(pool, type);
|
||||
LOGGER.info("数据库连接初始化: URL=" + url);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,7 +82,7 @@ public class JDBCPoolInit {
|
||||
*
|
||||
* @return pool
|
||||
*/
|
||||
public JDBCPool getPool() {
|
||||
synchronized public JDBCPool getPool() {
|
||||
return pool;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,19 +132,23 @@ public final class Deploy {
|
||||
localMap.put(GLOBAL_CONFIG, globalConfig);
|
||||
localMap.put(CUSTOM_CONFIG, customConfig);
|
||||
localMap.put(SERVER, globalConfig.getJsonObject(SERVER));
|
||||
var future0 = vertx.createSharedWorkerExecutor("other-handle").executeBlocking(bch -> {
|
||||
handle.handle(globalConfig);
|
||||
bch.complete("other handle complete");
|
||||
});
|
||||
var future0 = vertx.createSharedWorkerExecutor("other-handle")
|
||||
.executeBlocking(() -> {
|
||||
handle.handle(globalConfig);
|
||||
return "Other handle complete";
|
||||
});
|
||||
|
||||
// 部署 路由、异步service、反向代理 服务
|
||||
var future1 = vertx.deployVerticle(RouterVerticle.class, getWorkDeploymentOptions("Router"));
|
||||
var future2 = vertx.deployVerticle(ServiceVerticle.class, getWorkDeploymentOptions("Service"));
|
||||
var future3 = vertx.deployVerticle(ReverseProxyVerticle.class, getWorkDeploymentOptions("proxy"));
|
||||
future0.onSuccess(res -> {
|
||||
LOGGER.info(res);
|
||||
// 部署 路由、异步service、反向代理 服务
|
||||
var future1 = vertx.deployVerticle(RouterVerticle.class, getWorkDeploymentOptions("Router"));
|
||||
var future2 = vertx.deployVerticle(ServiceVerticle.class, getWorkDeploymentOptions("Service"));
|
||||
var future3 = vertx.deployVerticle(ReverseProxyVerticle.class, getWorkDeploymentOptions("proxy"));
|
||||
|
||||
CompositeFuture.all(future1, future2, future3, future0)
|
||||
.onSuccess(this::deployWorkVerticalSuccess)
|
||||
.onFailure(this::deployVerticalFailed);
|
||||
Future.all(future1, future2, future3)
|
||||
.onSuccess(this::deployWorkVerticalSuccess)
|
||||
.onFailure(this::deployVerticalFailed);
|
||||
}).onFailure(e -> LOGGER.error("Other handle error", e));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,6 +38,7 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static cn.qaiu.vx.core.util.ConfigConstant.ROUTE_TIME_OUT;
|
||||
import static cn.qaiu.vx.core.verticle.ReverseProxyVerticle.REROUTE_PATH_PREFIX;
|
||||
import static io.vertx.core.http.HttpHeaders.*;
|
||||
import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME;
|
||||
|
||||
@@ -72,20 +73,15 @@ public class RouterHandlerFactory implements BaseHttpApi {
|
||||
public Router createRouter() {
|
||||
// 主路由
|
||||
Router mainRouter = Router.router(VertxHolder.getVertxInstance());
|
||||
|
||||
// 静态资源
|
||||
String path = SharedDataUtil.getJsonConfig("server")
|
||||
.getString("staticResourcePath");
|
||||
if (!StringUtils.isEmpty(path)) {
|
||||
// 静态资源
|
||||
mainRouter.route("/*").handler(StaticHandler
|
||||
.create(path)
|
||||
.setCachingEnabled(true)
|
||||
.setDefaultContentEncoding("UTF-8"));
|
||||
}
|
||||
|
||||
|
||||
mainRouter.route().handler(ctx -> {
|
||||
String realPath = ctx.request().uri();;
|
||||
if (realPath.startsWith(REROUTE_PATH_PREFIX)) {
|
||||
// vertx web proxy暂不支持rewrite, 所以这里进行手动替换, 请求地址中的请求path前缀替换为originPath
|
||||
String rePath = realPath.substring(REROUTE_PATH_PREFIX.length());
|
||||
ctx.reroute(rePath);
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER.debug("The HTTP service request address information ===>path:{}, uri:{}, method:{}",
|
||||
ctx.request().path(), ctx.request().absoluteURI(), ctx.request().method());
|
||||
ctx.response().headers().add(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
|
||||
|
||||
@@ -6,13 +6,13 @@ import io.vertx.core.Future;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.http.HttpClient;
|
||||
import io.vertx.core.http.HttpServer;
|
||||
import io.vertx.core.http.WebSocket;
|
||||
import io.vertx.core.http.HttpServerOptions;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.core.net.PemKeyCertOptions;
|
||||
import io.vertx.ext.web.Route;
|
||||
import io.vertx.ext.web.Router;
|
||||
import io.vertx.ext.web.handler.StaticHandler;
|
||||
import io.vertx.ext.web.handler.sockjs.SockJSHandler;
|
||||
import io.vertx.ext.web.handler.sockjs.SockJSHandlerOptions;
|
||||
import io.vertx.ext.web.proxy.handler.ProxyHandler;
|
||||
import io.vertx.httpproxy.HttpProxy;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -40,10 +40,12 @@ public class ReverseProxyVerticle extends AbstractVerticle {
|
||||
.getJsonConfig(ConfigConstant.GLOBAL_CONFIG)
|
||||
.getString("proxyConf");
|
||||
private static final Future<JsonObject> CONFIG = ConfigUtil.readYamlConfig(PATH_PROXY_CONFIG);
|
||||
private static final String DEFAULT_PATH_404 = "webroot/err/404.html";
|
||||
private static final String DEFAULT_PATH_404 = "webroot/err/page404.html";
|
||||
|
||||
private static String serverName = "Vert.x-proxy-server"; //Server name in Http response header
|
||||
|
||||
public static String REROUTE_PATH_PREFIX = "/__rrvpspp"; //re_route_vert_proxy_server_path_prefix 硬编码
|
||||
|
||||
|
||||
@Override
|
||||
public void start(Promise<Void> startPromise) throws Exception {
|
||||
@@ -74,22 +76,24 @@ public class ReverseProxyVerticle extends AbstractVerticle {
|
||||
* @param proxyConf 代理配置
|
||||
*/
|
||||
private void handleProxyConf(JsonObject proxyConf) {
|
||||
// 404 path
|
||||
if (proxyConf.containsKey("404")) {
|
||||
// page404 path
|
||||
if (proxyConf.containsKey(
|
||||
|
||||
"page404")) {
|
||||
System.getProperty("user.dir");
|
||||
String path = proxyConf.getString("404");
|
||||
String path = proxyConf.getString("page404");
|
||||
if (StringUtils.isEmpty(path)) {
|
||||
proxyConf.put("404", DEFAULT_PATH_404);
|
||||
proxyConf.put("page404", DEFAULT_PATH_404);
|
||||
} else {
|
||||
if (!path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
if (!new File(System.getProperty("user.dir") + path).exists()) {
|
||||
proxyConf.put("404", DEFAULT_PATH_404);
|
||||
proxyConf.put("page404", DEFAULT_PATH_404);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
proxyConf.put("404", DEFAULT_PATH_404);
|
||||
proxyConf.put("page404", DEFAULT_PATH_404);
|
||||
}
|
||||
|
||||
final HttpClient httpClient = VertxHolder.getVertxInstance().createHttpClient();
|
||||
@@ -111,17 +115,12 @@ public class ReverseProxyVerticle extends AbstractVerticle {
|
||||
handleStatic(proxyConf.getJsonObject("static"), proxyRouter);
|
||||
}
|
||||
|
||||
// static server
|
||||
if (proxyConf.containsKey("sock")) {
|
||||
handleSock(proxyConf.getJsonArray("sock"), httpClient, proxyRouter);
|
||||
}
|
||||
|
||||
// Send 404 page
|
||||
// Send page404 page
|
||||
proxyRouter.errorHandler(404, ctx -> {
|
||||
ctx.response().sendFile(proxyConf.getString("404"));
|
||||
ctx.response().sendFile(proxyConf.getString("page404"));
|
||||
});
|
||||
|
||||
HttpServer server = vertx.createHttpServer();
|
||||
HttpServer server = getHttpsServer(proxyConf);
|
||||
server.requestHandler(proxyRouter);
|
||||
|
||||
Integer port = proxyConf.getInteger("listen");
|
||||
@@ -129,6 +128,38 @@ public class ReverseProxyVerticle extends AbstractVerticle {
|
||||
server.listen(port);
|
||||
}
|
||||
|
||||
private HttpServer getHttpsServer(JsonObject proxyConf) {
|
||||
HttpServerOptions httpServerOptions = new HttpServerOptions();
|
||||
if (proxyConf.containsKey("ssl")) {
|
||||
JsonObject sslConfig = proxyConf.getJsonObject("ssl");
|
||||
|
||||
URL sslUrl = this.getClass().getClassLoader().getResource("");
|
||||
if (sslUrl == null) {
|
||||
throw new RuntimeException("SSL url not exist...");
|
||||
}
|
||||
if (sslConfig.containsKey("enable") && sslConfig.getBoolean("enable")) {
|
||||
String sslCertificatePath = sslUrl.getPath() + sslConfig.getString("ssl_certificate");
|
||||
String sslCertificateKeyPath = sslUrl.getPath() + sslConfig.getString("ssl_certificate_key");
|
||||
LOGGER.info("enable ssl config. ");
|
||||
httpServerOptions
|
||||
.setSsl(true)
|
||||
.setKeyCertOptions(
|
||||
new PemKeyCertOptions()
|
||||
.setKeyPath(sslCertificateKeyPath)
|
||||
.setCertPath(sslCertificatePath)
|
||||
).addEnabledSecureTransportProtocol(sslConfig.getString("ssl_protocols"));
|
||||
String sslCiphers = sslConfig.getString("ssl_ciphers");
|
||||
if (sslCiphers != null && !sslCiphers.isEmpty()) {
|
||||
for (String s : sslCiphers.split(":")) {
|
||||
httpServerOptions.addEnabledCipherSuite(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return vertx.createHttpServer(httpServerOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理静态资源配置
|
||||
*
|
||||
@@ -145,9 +176,12 @@ public class ReverseProxyVerticle extends AbstractVerticle {
|
||||
ctx.next();
|
||||
});
|
||||
|
||||
final StaticHandler staticHandler = StaticHandler.create();
|
||||
|
||||
StaticHandler staticHandler;
|
||||
if (staticConf.containsKey("root")) {
|
||||
staticHandler.setWebRoot(staticConf.getString("root"));
|
||||
staticHandler = StaticHandler.create(staticConf.getString("root"));
|
||||
} else {
|
||||
staticHandler = StaticHandler.create();
|
||||
}
|
||||
if (staticConf.containsKey("directory-listing")) {
|
||||
staticHandler.setDirectoryListing(staticConf.getBoolean("directory-listing"));
|
||||
@@ -178,7 +212,7 @@ public class ReverseProxyVerticle extends AbstractVerticle {
|
||||
port = 80;
|
||||
}
|
||||
String originPath = url.getPath();
|
||||
LOGGER.debug("Conf(path, originPath, host, port) ----> {},{},{},{}", path, originPath, host, port);
|
||||
LOGGER.info("Conf(path, originPath, host, port) ----> {},{},{},{}", path, originPath, host, port);
|
||||
|
||||
// 注意这里不能origin多个代理地址, 一个实例只能代理一个origin
|
||||
final HttpProxy httpProxy = HttpProxy.reverseProxy(httpClient);
|
||||
@@ -189,14 +223,21 @@ public class ReverseProxyVerticle extends AbstractVerticle {
|
||||
|
||||
// 代理目标路径为空 就像nginx一样路径穿透 (相对路径)
|
||||
if (StringUtils.isEmpty(originPath) || path.equals(originPath)) {
|
||||
proxyRouter.route(path + "*").handler(ProxyHandler.create(httpProxy));
|
||||
Route route = path.startsWith("~") ? proxyRouter.routeWithRegex(path.substring(1))
|
||||
: proxyRouter.route(path);
|
||||
route.handler(ProxyHandler.create(httpProxy));
|
||||
} else {
|
||||
proxyRouter.route(originPath + "*").handler(ProxyHandler.create(httpProxy));
|
||||
proxyRouter.route(path + "*").handler(ctx -> {
|
||||
String realPath = ctx.request().path();
|
||||
if (realPath.startsWith(path)) {
|
||||
// 配置 /api/, / => 请求 /api/test 代理后 /test
|
||||
// 配置 /api/, /xxx => 请求 /api/test 代理后 /xxx/test
|
||||
final String path0 = path;
|
||||
final String originPath0 = REROUTE_PATH_PREFIX + originPath;
|
||||
|
||||
proxyRouter.route(originPath0 + "*").handler(ProxyHandler.create(httpProxy));
|
||||
proxyRouter.route(path0 + "*").handler(ctx -> {
|
||||
String realPath = ctx.request().uri();
|
||||
if (realPath.startsWith(path0)) {
|
||||
// vertx web proxy暂不支持rewrite, 所以这里进行手动替换, 请求地址中的请求path前缀替换为originPath
|
||||
String rePath = realPath.replaceAll("^" + path, originPath);
|
||||
String rePath = realPath.replaceAll("^" + path0, originPath0);
|
||||
ctx.reroute(rePath);
|
||||
} else {
|
||||
ctx.next();
|
||||
@@ -210,54 +251,4 @@ public class ReverseProxyVerticle extends AbstractVerticle {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理websocket
|
||||
*
|
||||
* @param confList sock配置
|
||||
* @param httpClient 客户端
|
||||
* @param proxyRouter 代理路由
|
||||
*/
|
||||
private void handleSock(JsonArray confList, HttpClient httpClient, Router proxyRouter) {
|
||||
// 代理规则
|
||||
confList.stream().map(e -> (JsonObject) e).forEach(conf -> {
|
||||
|
||||
String origin = conf.getString("origin");
|
||||
String path = conf.getString("path");
|
||||
LOGGER.info("websocket proxy: {}, {}",origin,path);
|
||||
|
||||
SockJSHandlerOptions options = new SockJSHandlerOptions()
|
||||
.setHeartbeatInterval(2000)
|
||||
.setRegisterWriteHandler(true);
|
||||
|
||||
SockJSHandler sockJSHandler = SockJSHandler.create(VertxHolder.getVertxInstance(), options);
|
||||
if (!path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
|
||||
|
||||
Router route = sockJSHandler.socketHandler(sock -> {
|
||||
sock.handler(buffer -> {
|
||||
Future<WebSocket> webSocketFuture = httpClient.webSocket(8086,"127.0.0.1",sock.uri());
|
||||
webSocketFuture.onSuccess(s -> {
|
||||
System.out.println(buffer.toString());
|
||||
s.write(buffer).onSuccess(v -> {
|
||||
s.handler(w->{
|
||||
System.out.println("--------"+w.toString());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
sock.endHandler(v -> {
|
||||
|
||||
});
|
||||
sock.closeHandler(v -> {
|
||||
|
||||
});
|
||||
});
|
||||
proxyRouter.mountSubRouter("/real/serverApi/test", route);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
10
note.txt
10
note.txt
@@ -22,3 +22,13 @@ Cloudreve自建网盘 (ce) {origin}/s/{shareKey}
|
||||
|
||||
|
||||
https://f.ws59.cn/f/e3peohu6192
|
||||
|
||||
开源版 TODO
|
||||
1. 缓存优化, 配置自动重载
|
||||
|
||||
|
||||
专属版 功能设计
|
||||
1. 支持绑定域名, 后台管理-账号管理, token管理, 账号解析次数限制
|
||||
2. 流量统计, 文件分享信息, 目录解析, 文件云下载
|
||||
3. IP代理池
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ package cn.qaiu.entity;
|
||||
public class ShareLinkInfo {
|
||||
|
||||
private String shareKey; // 分享键
|
||||
|
||||
private String panName; // 网盘名称
|
||||
private String type; // 分享类型
|
||||
private String sharePassword; // 分享密码(如果存在)
|
||||
private String shareUrl; // 原始分享链接
|
||||
@@ -10,6 +12,7 @@ public class ShareLinkInfo {
|
||||
|
||||
private ShareLinkInfo(Builder builder) {
|
||||
this.shareKey = builder.shareKey;
|
||||
this.panName = builder.panName;
|
||||
this.type = builder.type;
|
||||
this.sharePassword = builder.sharePassword;
|
||||
this.shareUrl = builder.shareUrl;
|
||||
@@ -22,10 +25,18 @@ public class ShareLinkInfo {
|
||||
return shareKey;
|
||||
}
|
||||
|
||||
public String getPanName() {
|
||||
return panName;
|
||||
}
|
||||
|
||||
public void setShareKey(String shareKey) {
|
||||
this.shareKey = shareKey;
|
||||
}
|
||||
|
||||
public void setPanName(String panName) {
|
||||
this.panName = panName;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
@@ -58,6 +69,12 @@ public class ShareLinkInfo {
|
||||
this.standardUrl = standardUrl;
|
||||
}
|
||||
|
||||
public String getCacheKey() {
|
||||
// 将type和shareKey组合成一个字符串作为缓存key
|
||||
return type + ":" + shareKey;
|
||||
}
|
||||
|
||||
|
||||
// 静态方法创建建造者对象
|
||||
public static ShareLinkInfo.Builder newBuilder() {
|
||||
return new ShareLinkInfo.Builder();
|
||||
@@ -65,6 +82,7 @@ public class ShareLinkInfo {
|
||||
|
||||
// 建造者类
|
||||
public static class Builder {
|
||||
public String panName; // 分享网盘名称
|
||||
private String shareKey; // 分享键
|
||||
private String type; // 分享类型 (网盘模板枚举的小写)
|
||||
private String sharePassword = ""; // 分享密码(如果存在)
|
||||
@@ -76,6 +94,11 @@ public class ShareLinkInfo {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder panName(String panName) {
|
||||
this.panName = panName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder type(String type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
@@ -105,6 +128,7 @@ public class ShareLinkInfo {
|
||||
public String toString() {
|
||||
return "ShareLinkInfo{" +
|
||||
"shareKey='" + shareKey + '\'' +
|
||||
", panName='" + panName + '\'' +
|
||||
", type='" + type + '\'' +
|
||||
", sharePassword='" + sharePassword + '\'' +
|
||||
", shareUrl='" + shareUrl + '\'' +
|
||||
|
||||
@@ -4,6 +4,9 @@ import cn.qaiu.WebClientVertxInit;
|
||||
import cn.qaiu.entity.ShareLinkInfo;
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.json.DecodeException;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.client.HttpResponse;
|
||||
import io.vertx.ext.web.client.WebClient;
|
||||
import io.vertx.ext.web.client.WebClientOptions;
|
||||
import io.vertx.ext.web.client.WebClientSession;
|
||||
@@ -98,4 +101,19 @@ public abstract class PanBase {
|
||||
return t -> fail(this.getClass().getSimpleName() + " - 请求异常 {}: -> {}", errorMsg, t.fillInStackTrace());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bodyAsJsonObject的封装, 会自动处理异常
|
||||
* @param res HttpResponse
|
||||
* @return JsonObject
|
||||
*/
|
||||
protected JsonObject asJson(HttpResponse<?> res) {
|
||||
try {
|
||||
return res.bodyAsJsonObject();
|
||||
} catch (DecodeException e) {
|
||||
fail("解析失败: json格式异常: {}", res.bodyAsString());
|
||||
throw new RuntimeException("解析失败: json格式异常");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public enum PanDomainTemplate {
|
||||
|
||||
// 网盘定义
|
||||
LZ("蓝奏云",
|
||||
"https://([a-z]+)?\\.?lanzou[a-z]\\.com/(.+/)?(.+)",
|
||||
"https://([a-z0-9-]+)?\\.?lanzou[a-z]\\.com/(.+/)?(.+)",
|
||||
"https://lanzoux.com/{shareKey}",
|
||||
LzTool.class),
|
||||
|
||||
@@ -52,12 +52,12 @@ public enum PanDomainTemplate {
|
||||
QQTool.class),
|
||||
// https://f.ws59.cn/f/或者https://www.wenshushu.cn/f/
|
||||
WS("文叔叔",
|
||||
"https://(f\\.ws59\\.cn|www\\.wenshushu\\.cn)/f/(.+)",
|
||||
"https://f.ws59.cn/f/{shareKey}",
|
||||
"https://(f\\.ws([0-9]{2})\\.cn|www\\.wenshushu\\.cn)/f/(.+)",
|
||||
"https://www.wenshushu.cn/f/{shareKey}",
|
||||
WsTool.class),
|
||||
// https://www.123pan.com/s/
|
||||
YE("123网盘",
|
||||
"https://www\\.123pan\\.com/s/(.+)",
|
||||
"https://www\\.(123pan|123865|123684)\\.com/s/(.+)",
|
||||
"https://www.123pan.com/s/{shareKey}",
|
||||
YeTool.class),
|
||||
// https://www.ecpan.cn/web/#/yunpanProxy?path=%2F%23%2Fdrive%2Foutside&data={code}&isShare=1
|
||||
@@ -71,10 +71,11 @@ public enum PanDomainTemplate {
|
||||
"https://(.*)cowtransfer\\.com/s/(.+)",
|
||||
"https://cowtransfer.com/s/{shareKey}",
|
||||
CowTool.class),
|
||||
// https://pan.huang1111.cn/s/
|
||||
CE("huang1111",
|
||||
"https://pan\\.huang1111\\.cn/s/(.+)",
|
||||
"https://pan.huang1111.cn/s/{shareKey}",
|
||||
// https://pan.huang1111.cn/s/xxx
|
||||
// 通用域名([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}
|
||||
CE("Cloudreve",
|
||||
"https://([a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,}/s/(.+)",
|
||||
"https://{CloudreveDomainName}/s/{shareKey}",
|
||||
CeTool.class);
|
||||
|
||||
|
||||
|
||||
@@ -42,7 +42,9 @@ public class ParserCreate {
|
||||
String standardUrl = getStandardUrlTemplate().replace("{shareKey}", shareKey);
|
||||
shareLinkInfo.setShareUrl(shareUrl);
|
||||
shareLinkInfo.setShareKey(shareKey);
|
||||
shareLinkInfo.setStandardUrl(standardUrl);
|
||||
if (!(panDomainTemplate == PanDomainTemplate.CE)) {
|
||||
shareLinkInfo.setStandardUrl(standardUrl);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid share URL for " + this.panDomainTemplate.getDisplayName());
|
||||
@@ -66,8 +68,17 @@ public class ParserCreate {
|
||||
|
||||
// set share key
|
||||
public ParserCreate shareKey(String shareKey) {
|
||||
shareLinkInfo.setShareKey(shareKey);
|
||||
shareLinkInfo.setStandardUrl(panDomainTemplate.getStandardUrlTemplate().replace("{shareKey}", shareKey));
|
||||
if (panDomainTemplate == PanDomainTemplate.CE) {
|
||||
// 处理Cloudreve(ce)类: pan.huang1111.cn_s_wDz5TK _ -> /
|
||||
String[] s = shareKey.split("_");
|
||||
String standardUrl = "https://" + String.join("/", s);
|
||||
shareLinkInfo.setShareKey(s[s.length - 1]);
|
||||
shareLinkInfo.setStandardUrl(standardUrl);
|
||||
shareLinkInfo.setShareUrl(standardUrl);
|
||||
} else {
|
||||
shareLinkInfo.setShareKey(shareKey);
|
||||
shareLinkInfo.setStandardUrl(panDomainTemplate.getStandardUrlTemplate().replace("{shareKey}", shareKey));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -90,7 +101,11 @@ public class ParserCreate {
|
||||
if (shareUrl.matches(panDomainTemplate.getRegexPattern())) {
|
||||
ShareLinkInfo shareLinkInfo = ShareLinkInfo.newBuilder()
|
||||
.type(panDomainTemplate.name().toLowerCase())
|
||||
.panName(panDomainTemplate.getDisplayName())
|
||||
.shareUrl(shareUrl).build();
|
||||
if (panDomainTemplate == PanDomainTemplate.CE) {
|
||||
shareLinkInfo.setStandardUrl(shareUrl);
|
||||
}
|
||||
ParserCreate parserCreate = new ParserCreate(panDomainTemplate, shareLinkInfo);
|
||||
return parserCreate.normalizeShareLink();
|
||||
}
|
||||
@@ -110,4 +125,21 @@ public class ParserCreate {
|
||||
throw new IllegalArgumentException("No enum constant for type name: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
// 生成parser短链path(不包含domainName)
|
||||
public String genPathSuffix() {
|
||||
|
||||
String path;
|
||||
if (panDomainTemplate == PanDomainTemplate.CE) {
|
||||
// 处理Cloudreve(ce)类: pan.huang1111.cn_s_wDz5TK _ -> /
|
||||
path = this.shareLinkInfo.getType() + "/"
|
||||
+ this.shareLinkInfo.getShareUrl()
|
||||
.substring("https://".length()).replace("/", "_");
|
||||
} else {
|
||||
path = this.shareLinkInfo.getType() + "/" + this.shareLinkInfo.getShareKey();
|
||||
}
|
||||
String sharePassword = this.shareLinkInfo.getSharePassword();
|
||||
return path + (StringUtils.isBlank(sharePassword) ? "" : ("@" + sharePassword));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,17 +8,21 @@ import io.vertx.core.buffer.Buffer;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.client.HttpRequest;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* <a href="https://github.com/cloudreve/Cloudreve">Cloudreve网盘解析</a> <br>
|
||||
* <a href="https://github.com/cloudreve/Cloudreve">Cloudreve自建网盘解析</a> <br>
|
||||
* <a href="https://pan.xiaomuxi.cn">暮希云盘</a> <br>
|
||||
* <a href="https://pan.huang1111.cn">huang1111</a> <br>
|
||||
* <a href="https://pan.seeoss.com">看见存储</a> <br>
|
||||
* <a href="https://dav.yiandrive.com">亿安云盘</a> <br>
|
||||
*/
|
||||
public class CeTool extends PanBase implements IPanTool {
|
||||
|
||||
private static final String DOWNLOAD_API_PATH = "https://pan.huang1111.cn/api/v3/share/download/";
|
||||
private static final String DOWNLOAD_API_PATH = "/api/v3/share/download/";
|
||||
|
||||
// api/v3/share/info/g31PcQ?password=qaiu
|
||||
private static final String SHARE_API_PATH = "https://pan.huang1111.cn/api/v3/share/info/";
|
||||
private static final String SHARE_API_PATH = "/api/v3/share/info/";
|
||||
|
||||
public CeTool(ShareLinkInfo shareLinkInfo) {
|
||||
super(shareLinkInfo);
|
||||
@@ -31,24 +35,14 @@ public class CeTool extends PanBase implements IPanTool {
|
||||
// https://pan.huang1111.cn/s/wDz5TK
|
||||
// https://pan.huang1111.cn/s/y12bI6 -> https://pan.huang1111
|
||||
// .cn/api/v3/share/download/y12bI6?path=undefined%2Fundefined;
|
||||
// 类型解析 -> /ce/https_pan.huang1111.cn_s_wDz5TK
|
||||
// 类型解析 -> /ce/pan.huang1111.cn_s_wDz5TK
|
||||
// parser接口 -> /parser?url=https://pan.huang1111.cn/s/wDz5TK
|
||||
try {
|
||||
// if (key.startsWith("https_") || key.startsWith("http_")) {
|
||||
// key = key.replace("https_", "https://")
|
||||
// .replace("http_", "http://")
|
||||
// .replace("_", "/");
|
||||
// }
|
||||
// // 处理URL
|
||||
// URL url = new URL(key);
|
||||
// String path = url.getPath();
|
||||
// String shareKey = path.substring(3);
|
||||
// String downloadApiUrl = url.getProtocol() + "://" + url.getHost() + DOWNLOAD_API_PATH + shareKey + "?path" +
|
||||
// "=undefined/undefined;";
|
||||
// String shareApiUrl = url.getProtocol() + "://" + url.getHost() + SHARE_API_PATH + shareKey;
|
||||
|
||||
var shareApiUrl = SHARE_API_PATH;
|
||||
var downloadApiUrl = DOWNLOAD_API_PATH;
|
||||
URL url = new URL(shareLinkInfo.getShareUrl());
|
||||
String downloadApiUrl = url.getProtocol() + "://" + url.getHost() + DOWNLOAD_API_PATH + key + "?path" +
|
||||
"=undefined/undefined;";
|
||||
String shareApiUrl = url.getProtocol() + "://" + url.getHost() + SHARE_API_PATH + key;
|
||||
|
||||
// 设置cookie
|
||||
HttpRequest<Buffer> httpRequest = clientSession.getAbs(shareApiUrl);
|
||||
@@ -65,7 +59,7 @@ public class CeTool extends PanBase implements IPanTool {
|
||||
|
||||
private void getDownURL(String apiUrl) {
|
||||
clientSession.putAbs(apiUrl).send().onSuccess(res -> {
|
||||
JsonObject jsonObject = res.bodyAsJsonObject();
|
||||
JsonObject jsonObject = asJson(res);
|
||||
System.out.println(jsonObject.encodePrettily());
|
||||
if (jsonObject.containsKey("code") && jsonObject.getInteger("code") == 0) {
|
||||
promise.complete(jsonObject.getString("data"));
|
||||
|
||||
@@ -26,7 +26,7 @@ public class CowTool extends PanBase implements IPanTool {
|
||||
final String key = shareLinkInfo.getShareKey();
|
||||
String url = API_REQUEST_URL + "?uniqueUrl=" + key;
|
||||
client.getAbs(url).send().onSuccess(res -> {
|
||||
JsonObject resJson = res.bodyAsJsonObject();
|
||||
JsonObject resJson = asJson(res);
|
||||
if ("success".equals(resJson.getString("message")) && resJson.containsKey("data")) {
|
||||
JsonObject dataJson = resJson.getJsonObject("data");
|
||||
String guid = dataJson.getString("guid");
|
||||
@@ -41,7 +41,7 @@ public class CowTool extends PanBase implements IPanTool {
|
||||
}
|
||||
String url2 = url2Build.toString();
|
||||
client.getAbs(url2).send().onSuccess(res2 -> {
|
||||
JsonObject res2Json = res2.bodyAsJsonObject();
|
||||
JsonObject res2Json = asJson(res2);
|
||||
if ("success".equals(res2Json.getString("message")) && res2Json.containsKey("data")) {
|
||||
JsonObject data2 = res2Json.getJsonObject("data");
|
||||
String downloadUrl = data2.getString("downloadUrl");
|
||||
|
||||
@@ -34,7 +34,7 @@ public class EcTool extends PanBase implements IPanTool {
|
||||
.setTemplateParam("extractionCode", pwd == null ? "" : pwd)
|
||||
.send()
|
||||
.onSuccess(res -> {
|
||||
JsonObject jsonObject = res.bodyAsJsonObject();
|
||||
JsonObject jsonObject = asJson(res);
|
||||
log.debug("ecPan get file info -> {}", jsonObject);
|
||||
JsonObject fileInfo = jsonObject
|
||||
.getJsonObject("var")
|
||||
@@ -59,7 +59,7 @@ public class EcTool extends PanBase implements IPanTool {
|
||||
|
||||
// 第二次请求 获取下载链接
|
||||
client.postAbs(DOWNLOAD_REQUEST_URL).sendJsonObject(requestBodyJson).onSuccess(res2 -> {
|
||||
JsonObject jsonRes = res2.bodyAsJsonObject();
|
||||
JsonObject jsonRes = asJson(res2);
|
||||
log.debug("ecPan get download url -> {}", res2.body().toString());
|
||||
promise.complete(jsonRes.getJsonObject("var").getString("downloadUrl"));
|
||||
}).onFailure(handleFail(""));
|
||||
|
||||
@@ -88,7 +88,7 @@ public class FcTool extends PanBase implements IPanTool {
|
||||
.setTemplateParam("unique_name", dataKey).send().onSuccess(res2 -> {
|
||||
JsonObject resJson;
|
||||
try {
|
||||
resJson = res2.bodyAsJsonObject();
|
||||
resJson = asJson(res2);
|
||||
} catch (Exception e) {
|
||||
fail(e, DOWN_REQUEST_URL + " 第二次请求没有返回JSON, 可能下载受限");
|
||||
return;
|
||||
|
||||
@@ -63,7 +63,7 @@ public class FjTool extends PanBase implements IPanTool {
|
||||
.setTemplateParam("uuid", uuid)
|
||||
.setTemplateParam("ts", tsEncode0)
|
||||
.send().onSuccess(res -> {
|
||||
JsonObject resJson = res.bodyAsJsonObject();
|
||||
JsonObject resJson = asJson(res);
|
||||
if (resJson.getInteger("code") != 200) {
|
||||
fail(FIRST_REQUEST_URL + " 返回异常: " + resJson);
|
||||
return;
|
||||
|
||||
@@ -39,7 +39,7 @@ public class IzTool extends PanBase implements IPanTool {
|
||||
// 第一次请求 获取文件信息
|
||||
// POST https://api.feijipan.com/ws/recommend/list?devType=6&devModel=Chrome&extra=2&shareId=146731&type=0&offset=1&limit=60
|
||||
client.postAbs(UriTemplate.of(FIRST_REQUEST_URL)).setTemplateParam("shareId", dataKey).send().onSuccess(res -> {
|
||||
JsonObject resJson = res.bodyAsJsonObject();
|
||||
JsonObject resJson = asJson(res);
|
||||
if (resJson.getInteger("code") != 200) {
|
||||
fail(FIRST_REQUEST_URL + " 返回异常: " + resJson);
|
||||
return;
|
||||
|
||||
@@ -27,7 +27,7 @@ public class LeTool extends PanBase implements IPanTool {
|
||||
client.postAbs(apiUrl1)
|
||||
.sendJsonObject(JsonObject.of("shareId", dataKey, "password", pwd, "directoryId", -1))
|
||||
.onSuccess(res -> {
|
||||
JsonObject resJson = res.bodyAsJsonObject();
|
||||
JsonObject resJson = asJson(res);
|
||||
if (resJson.containsKey("result")) {
|
||||
if (resJson.getBoolean("result")) {
|
||||
JsonObject dataJson = resJson.getJsonObject("data");
|
||||
@@ -68,7 +68,7 @@ public class LeTool extends PanBase implements IPanTool {
|
||||
client.postAbs(apiUrl2)
|
||||
.sendJsonObject(JsonObject.of("fileIds", fileIds, "shareId", key, "browserId", uuid))
|
||||
.onSuccess(res -> {
|
||||
JsonObject resJson = res.bodyAsJsonObject();
|
||||
JsonObject resJson = asJson(res);
|
||||
if (resJson.containsKey("result")) {
|
||||
if (resJson.getBoolean("result")) {
|
||||
JsonObject dataJson = resJson.getJsonObject("data");
|
||||
|
||||
@@ -115,7 +115,7 @@ public class LzTool extends PanBase implements IPanTool {
|
||||
|
||||
String url = SHARE_URL_PREFIX + "/ajaxm.php";
|
||||
client.postAbs(url).putHeaders(headers).sendForm(map).onSuccess(res2 -> {
|
||||
JsonObject urlJson = res2.bodyAsJsonObject();
|
||||
JsonObject urlJson = asJson(res2);
|
||||
if (urlJson.getInteger("zt") != 1) {
|
||||
fail(urlJson.getString("inf"));
|
||||
return;
|
||||
|
||||
@@ -50,7 +50,7 @@ public class WsTool extends PanBase implements IPanTool {
|
||||
if (res.statusCode() == 200) {
|
||||
try {
|
||||
// 设置匿名登录token
|
||||
String token = res.bodyAsJsonObject().getJsonObject("data").getString("token");
|
||||
String token = asJson(res).getJsonObject("data").getString("token");
|
||||
headers.set("X-Token", token);
|
||||
|
||||
// 获取文件夹信息
|
||||
@@ -63,10 +63,10 @@ public class WsTool extends PanBase implements IPanTool {
|
||||
if (res2.statusCode() == 200) {
|
||||
try {
|
||||
// 获取文件夹信息
|
||||
String filetime = res2.bodyAsJsonObject().getJsonObject("data").getString("expire"); // 文件夹剩余时间
|
||||
String filesize = res2.bodyAsJsonObject().getJsonObject("data").getString("file_size"); // 文件夹大小
|
||||
String filepid = res2.bodyAsJsonObject().getJsonObject("data").getString("ufileid"); // 文件夹pid
|
||||
String filebid = res2.bodyAsJsonObject().getJsonObject("data").getString("boxid"); // 文件夹bid
|
||||
String filetime = asJson(res2).getJsonObject("data").getString("expire"); // 文件夹剩余时间
|
||||
String filesize = asJson(res2).getJsonObject("data").getString("file_size"); // 文件夹大小
|
||||
String filepid = asJson(res2).getJsonObject("data").getString("ufileid"); // 文件夹pid
|
||||
String filebid = asJson(res2).getJsonObject("data").getString("boxid"); // 文件夹bid
|
||||
|
||||
// 调试输出文件夹信息
|
||||
System.out.println("文件夹期限: " + filetime);
|
||||
@@ -93,9 +93,9 @@ public class WsTool extends PanBase implements IPanTool {
|
||||
if (res3.statusCode() == 200) {
|
||||
try {
|
||||
// 获取文件信息
|
||||
String filename = res3.bodyAsJsonObject().getJsonObject("data")
|
||||
String filename = asJson(res3).getJsonObject("data")
|
||||
.getJsonArray("fileList").getJsonObject(0).getString("fname"); // 文件名称
|
||||
String filefid = res3.bodyAsJsonObject().getJsonObject("data")
|
||||
String filefid = asJson(res3).getJsonObject("data")
|
||||
.getJsonArray("fileList").getJsonObject(0).getString("fid"); // 文件fid
|
||||
|
||||
// 调试输出文件信息
|
||||
@@ -113,7 +113,7 @@ public class WsTool extends PanBase implements IPanTool {
|
||||
if (res4.statusCode() == 200) {
|
||||
try {
|
||||
// 获取直链
|
||||
String fileurl = res4.bodyAsJsonObject().getJsonObject("data").getString("url");
|
||||
String fileurl = asJson(res4).getJsonObject("data").getString("url");
|
||||
|
||||
// 调试输出文件直链
|
||||
System.out.println("文件直链: " + fileurl);
|
||||
|
||||
@@ -70,7 +70,7 @@ public class YeTool extends PanBase implements IPanTool {
|
||||
.putHeader("Platform", "web")
|
||||
.putHeader("App-Version", "3")
|
||||
.send().onSuccess(res2 -> {
|
||||
JsonObject infoJson = res2.bodyAsJsonObject();
|
||||
JsonObject infoJson = asJson(res2);
|
||||
if (infoJson.getInteger("code") != 0) {
|
||||
fail("{} 状态码异常 {}", dataKey, infoJson);
|
||||
return;
|
||||
@@ -121,7 +121,7 @@ public class YeTool extends PanBase implements IPanTool {
|
||||
.putHeader("Platform", "web")
|
||||
.putHeader("App-Version", "3")
|
||||
.sendJsonObject(jsonObject).onSuccess(res2 -> {
|
||||
JsonObject downURLJson = res2.bodyAsJsonObject();
|
||||
JsonObject downURLJson = asJson(res2);
|
||||
|
||||
try {
|
||||
if (downURLJson.getInteger("code") != 0) {
|
||||
@@ -141,7 +141,7 @@ public class YeTool extends PanBase implements IPanTool {
|
||||
|
||||
// 获取直链
|
||||
client.getAbs(downUrl2).send().onSuccess(res3 -> {
|
||||
JsonObject res3Json = res3.bodyAsJsonObject();
|
||||
JsonObject res3Json = asJson(res3);
|
||||
try {
|
||||
if (res3Json.getInteger("code") != 0) {
|
||||
fail("Ye: downUrl2返回值异常->" + res3Json);
|
||||
|
||||
80
parser/src/main/java/cn/qaiu/util/IpExtractor.java
Normal file
80
parser/src/main/java/cn/qaiu/util/IpExtractor.java
Normal file
@@ -0,0 +1,80 @@
|
||||
package cn.qaiu.util;
|
||||
|
||||
import io.vertx.core.MultiMap;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.http.impl.headers.HeadersMultiMap;
|
||||
import io.vertx.ext.web.client.WebClient;
|
||||
import io.vertx.ext.web.client.WebClientSession;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class IpExtractor {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
|
||||
|
||||
// 创建请求头Map
|
||||
MultiMap headers = new HeadersMultiMap();
|
||||
headers.add("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
|
||||
headers.add("accept-language", "zh-CN,zh;q=0.9,en;q=0.8");
|
||||
headers.add("cache-control", "no-cache");
|
||||
headers.add("dnt", "1");
|
||||
headers.add("origin", "https://ip.ihuan.me");
|
||||
headers.add("pragma", "no-cache");
|
||||
headers.add("priority", "u=0, i");
|
||||
headers.add("referer", "https://ip.ihuan.me/ti.html");
|
||||
headers.add("sec-ch-ua", "\"Google Chrome\";v=\"129\", \"Not=A?Brand\";v=\"8\", \"Chromium\";v=\"129\"");
|
||||
headers.add("sec-ch-ua-mobile", "?0");
|
||||
headers.add("sec-ch-ua-platform", "\"Windows\"");
|
||||
headers.add("sec-fetch-dest", "document");
|
||||
headers.add("sec-fetch-mode", "navigate");
|
||||
headers.add("sec-fetch-site", "same-origin");
|
||||
headers.add("sec-fetch-user", "?1");
|
||||
headers.add("upgrade-insecure-requests", "1");
|
||||
headers.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36");
|
||||
headers.add("Content-Type", "application/x-www-form-urlencoded");
|
||||
|
||||
WebClient client = WebClient.create(Vertx.vertx());
|
||||
WebClientSession webClientSession = WebClientSession.create(client);
|
||||
webClientSession.getAbs("https://ip.ihuan.me").putHeaders(headers).send().onSuccess(res->{
|
||||
System.out.println(res.toString());
|
||||
webClientSession.getAbs("https://ip.ihuan.me").putHeaders(headers).send().onSuccess(res2->{
|
||||
System.out.println(res2.toString());
|
||||
|
||||
});
|
||||
});
|
||||
//
|
||||
// String htmlContent = "<div class=\"panel-heading\">提取结果</div>\n" +
|
||||
// "<div class=\"panel-body\">111.1.27.85:80<br>42.63.65.46:80<br>118.195.242.20:8080<br>42.63.65.119:80<br>117.50.108.90:7890<br>116.62.50.250:7890<br>114.231.8.177:8089<br>190.43.92.90:999<br>221.178.85.68:8080<br><br>61.160.202.86:80<br>42.63.65.86:80<br>42.63.65.7:80<br>42.63.65.41:80<br>159.226.227.119:80<br>61.160.202.52:80<br>42.63.65.15:80<br>112.17.16.204:80<br>61.160.202.53:80<br>42.63.65.9:80<br>42.63.65.60:80<br>42.63.65.18:80<br>203.190.115.177:8071<br>42.63.65.38:80<br>42.63.65.31:80<br>91.185.3.126:8080<br>139.9.119.20:80<br>1.15.47.213:443<br>183.164.243.108:8089<br>165.225.208.177:80<br>194.163.132.232:3128<br>91.235.220.122:80<br>39.100.120.200:7890<br>141.147.33.121:80<br>183.164.243.138:8089<br>104.129.205.94:54321<br>117.160.250.138:81<br>180.120.213.208:8089<br>61.130.9.37:443<br>182.34.18.206:9999<br>117.86.12.150:8089<br>27.192.173.108:9000<br>183.164.243.11:8089<br>114.231.41.205:8089<br>103.104.233.78:8080<br>183.164.243.174:8089<br>36.6.144.230:8089<br>111.224.213.239:8089<br>182.92.73.106:80<br>36.6.145.81:8089<br>117.69.232.125:8089<br>36.6.144.64:8089<br>117.57.92.20:8089<br>47.100.69.29:8888<br>117.57.93.246:8089<br>120.234.203.171:9002<br>114.231.46.231:8089<br>183.164.242.199:8089<br>117.69.237.179:8089<br>182.44.32.239:7890<br>47.100.91.57:8080<br>117.69.236.127:8089<br>114.231.8.18:8089<br>117.69.232.183:8089<br>117.69.237.29:8089<br>183.164.242.67:8089<br>183.164.242.35:8089<br>183.164.243.71:8089<br>113.223.214.155:8089<br>36.6.145.132:8089<br>182.106.220.252:9091<br>113.223.212.176:8089<br>62.152.53.186:8909<br>117.57.92.16:8089<br>183.164.243.186:8089<br>36.6.144.210:8089<br>183.164.242.189:8089<br>213.178.39.170:8080<br>121.52.145.163:8080<br>36.6.144.240:8089<br>60.188.5.234:80<br>113.223.213.48:8089<br>183.164.243.149:8089<br>200.58.87.195:8080<br>36.6.144.153:8089<br>36.6.144.67:8089<br>36.6.145.182:8089<br>117.57.93.226:8089<br>42.112.24.127:8888<br>43.138.20.156:80<br>117.57.92.79:8089<br>65.109.111.238:3128<br>183.166.137.201:41122<br>113.223.213.150:8089<br>36.6.145.154:8089<br>185.5.209.101:80<br>36.6.144.17:8089<br>114.231.8.244:8089<br>117.69.237.24:8089<br>117.69.236.232:8089<br>117.69.236.127:8089<br>114.231.8.18:8089<br>117.69.232.183:8089<br>117.69.237.29:8089<br>183.164.242.67:8089<br>183.164.242.35:8089<br>183.164.243.71:8089<br>113.223.214.155:8089<br>36.6.145.132:8089<br>182.106.220.252:9091<br>113.223.212.176:8089<br>62.152.53.186:8909<br>117.57.92.16:8089<br>183.164.243.186:8089<br>36.6.144.210:8089<br>183.164.242.189:8089<br>213.178.39.170:8080<br>121.52.145.163:8080<br>36.6.144.240:8089<br>60.188.5.234:80<br>113.223.213.48:8089<br>183.164.243.149:8089<br>200.58.87.195:8080<br>36.6.144.153:8089<br>36.6.144.67:8089<br>36.6.145.182:8089<br>117.57.93.226:8089<br>42.112.24.127:8888<br>43.138.20.156:80<br>117.57.92.79:8089<br>65.109.111.238:3128<br>183.166.137.201:41122<br>113.223.213.150:8089<br>36.6.145.154:8089<br>185.5.209.101:80<br>36.6.144.17:8089<br>114.231.8.244:8089<br>117.69.237.24:8089<br>117.69.236.232:8089</div>";
|
||||
//
|
||||
// // 正则表达式匹配提取结果关键字下面的IP地址
|
||||
// Pattern pattern = Pattern.compile("<div class=\"panel-heading\">提取结果</div>\\s*<div class=\"panel-body\">([\\s\\S]*?)(?=</div>)", Pattern.DOTALL);
|
||||
// Matcher matcher = pattern.matcher(htmlContent);
|
||||
//
|
||||
// if (matcher.find()) {
|
||||
// String ipText = matcher.group(1); // 获取匹配的IP地址部分
|
||||
// Pattern ipPattern = Pattern.compile("(?:[0-9]{1,3}\\.){3}[0-9]{1,3}(?::\\d+)?");
|
||||
// Matcher ipMatcher = ipPattern.matcher(ipText);
|
||||
//
|
||||
// List<String> ips = new ArrayList<>();
|
||||
// while (ipMatcher.find()) {
|
||||
// ips.add(ipMatcher.group());
|
||||
// }
|
||||
//
|
||||
// System.out.println("提取到的IP地址:");
|
||||
// for (String ip : ips) {
|
||||
//// System.out.println(ip);
|
||||
// }
|
||||
// } else {
|
||||
// System.out.println("没有找到匹配的IP地址");
|
||||
// }
|
||||
//
|
||||
// TimeUnit.SECONDS.sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
12
parser/src/main/java/cn/qaiu/util/PanExceptionUtils.java
Normal file
12
parser/src/main/java/cn/qaiu/util/PanExceptionUtils.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package cn.qaiu.util;
|
||||
|
||||
/**
|
||||
* @author <a href="https://qaiu.top">QAIU</a>
|
||||
* @date 2023/7/16 1:53
|
||||
*/
|
||||
public class PanExceptionUtils {
|
||||
|
||||
public static RuntimeException fillRunTimeException(String name, String dataKey, Throwable t) {
|
||||
return new RuntimeException(name + ": 请求异常: key = " + dataKey, t.fillInStackTrace());
|
||||
}
|
||||
}
|
||||
74
parser/src/main/java/cn/qaiu/util/ReqIpUtil.java
Normal file
74
parser/src/main/java/cn/qaiu/util/ReqIpUtil.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package cn.qaiu.util;
|
||||
|
||||
import io.vertx.core.AsyncResult;
|
||||
import io.vertx.core.MultiMap;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.buffer.Buffer;
|
||||
import io.vertx.core.http.impl.headers.HeadersMultiMap;
|
||||
import io.vertx.ext.web.client.HttpResponse;
|
||||
import io.vertx.ext.web.client.WebClient;
|
||||
import io.vertx.ext.web.client.WebClientSession;
|
||||
|
||||
public class ReqIpUtil {
|
||||
public static String BASE_URL = "https://ip.ihuan.me";
|
||||
public static String BASE_URL_TEMPLATE = BASE_URL + "/{path}";
|
||||
|
||||
// GET https://ip.ihuan.me/mouse.do -> $("input[name='key']").val("30b4975b5547fed806bd2b9caa18485a");
|
||||
public static String PATH1 = "mouse.do";
|
||||
|
||||
public static String PATH2 = "tqdl.html";
|
||||
|
||||
// 创建请求头Map
|
||||
static MultiMap headers = new HeadersMultiMap();
|
||||
|
||||
static {
|
||||
|
||||
headers.set("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
|
||||
headers.set("accept-language", "zh-CN,zh;q=0.9,en;q=0.8");
|
||||
headers.set("cache-control", "no-cache");
|
||||
headers.set("dnt", "1");
|
||||
headers.set("origin", "https://ip.ihuan.me");
|
||||
headers.set("pragma", "no-cache");
|
||||
headers.set("priority", "u=0, i");
|
||||
headers.set("referer", "https://ip.ihuan.me");
|
||||
headers.set("sec-ch-ua", "\"Google Chrome\";v=\"129\", \"Not=A?Brand\";v=\"8\", \"Chromium\";v=\"129\"");
|
||||
headers.set("sec-ch-ua-mobile", "?0");
|
||||
headers.set("sec-ch-ua-platform", "\"Windows\"");
|
||||
headers.set("sec-fetch-dest", "document");
|
||||
headers.set("sec-fetch-mode", "navigate");
|
||||
headers.set("sec-fetch-site", "same-origin");
|
||||
headers.set("sec-fetch-user", "?1");
|
||||
headers.set("upgrade-insecure-requests", "1");
|
||||
// headers.set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36");
|
||||
|
||||
}
|
||||
|
||||
|
||||
Vertx vertx = Vertx.vertx();
|
||||
WebClient webClient = WebClient.create(vertx);
|
||||
// 发送GET请求
|
||||
WebClientSession webClientSession = WebClientSession.create(webClient);
|
||||
|
||||
|
||||
public void exec() {
|
||||
webClientSession.getAbs(BASE_URL)
|
||||
.putHeaders(headers) // 将请求头Map添加到请求中
|
||||
.send(this::next);
|
||||
}
|
||||
|
||||
void next(AsyncResult<HttpResponse<Buffer>> response) {
|
||||
if (response.failed()) {
|
||||
response.cause().printStackTrace();
|
||||
} else {
|
||||
HttpResponse<Buffer> res = response.result();
|
||||
System.out.println("Received response with status code " + res.statusCode());
|
||||
System.out.println("Body: " + res.body());
|
||||
webClientSession.getAbs(BASE_URL_TEMPLATE).setTemplateParam("path", PATH1)
|
||||
.putHeaders(headers) // 将请求头Map添加到请求中
|
||||
.send(response2 -> {
|
||||
System.out.println(response2.result().bodyAsString());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
1
pom.xml
1
pom.xml
@@ -25,7 +25,6 @@
|
||||
|
||||
<packageDirectory>${project.basedir}/web-service/target/package</packageDirectory>
|
||||
|
||||
<slf4j.version>2.0.5</slf4j.version>
|
||||
<vertx.version>4.5.6</vertx.version>
|
||||
<org.reflections.version>0.10.2</org.reflections.version>
|
||||
<lombok.version>1.18.30</lombok.version>
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
# nfd-web
|
||||
当前页面修改自开源项目 https://github.com/HurryBy/CloudDiskAnalysis
|
||||
解析服务的前端页面, 提供API测试, 统计查询, 二维码生成等
|
||||

|
||||

|
||||

|
||||
|
||||
## 关于如何将前端项目和java一块打包:
|
||||
1. 先打包前端模块
|
||||
2. 打包后请将当前目录下的nfd-front目录放置在项目下webroot目录, 然后使用maven打包java模块即可
|
||||
3. 项目部署后演示页面的代理端口是6401默认使用http, 如需https可以加nginx代理, 也可以使用本项目自带的代理服务和配置证书路径
|
||||
|
||||

|
||||
## Project setup
|
||||
```
|
||||
npm install
|
||||
|
||||
BIN
web-front/img/img.png
Normal file
BIN
web-front/img/img.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
BIN
web-front/img/img_1.png
Normal file
BIN
web-front/img/img_1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
BIN
web-front/img/img_2.png
Normal file
BIN
web-front/img/img_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
249
web-front/package-lock.json
generated
249
web-front/package-lock.json
generated
@@ -10,8 +10,9 @@
|
||||
"dependencies": {
|
||||
"axios": "^1.7.4",
|
||||
"core-js": "^3.8.3",
|
||||
"element-ui": "^2.15.12",
|
||||
"vue": "^2.6.14",
|
||||
"element-ui": "^2.15.14",
|
||||
"qrcode": "^1.5.4",
|
||||
"vue": "^2.7.16",
|
||||
"vue-clipboard2": "^0.3.3",
|
||||
"vue-json-viewer": "^2.2.22"
|
||||
},
|
||||
@@ -25,7 +26,7 @@
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-plugin-vue": "^8.0.3",
|
||||
"filemanager-webpack-plugin": "8.0.0",
|
||||
"vue-template-compiler": "^2.6.14"
|
||||
"vue-template-compiler": "^2.7.16"
|
||||
}
|
||||
},
|
||||
"node_modules/@achrinza/node-ipc": {
|
||||
@@ -431,19 +432,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-string-parser": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
|
||||
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
|
||||
"dev": true,
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz",
|
||||
"integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
||||
"dev": true,
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
|
||||
"integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@@ -501,9 +500,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
|
||||
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
|
||||
"version": "7.25.6",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.25.6.tgz",
|
||||
"integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.25.6"
|
||||
},
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
@@ -1713,13 +1715,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
|
||||
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
|
||||
"dev": true,
|
||||
"version": "7.25.6",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.25.6.tgz",
|
||||
"integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.22.5",
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"@babel/helper-string-parser": "^7.24.8",
|
||||
"@babel/helper-validator-identifier": "^7.24.7",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -2878,13 +2879,16 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "2.7.14",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-2.7.14.tgz",
|
||||
"integrity": "sha512-aNmNHyLPsw+sVvlQFQ2/8sjNuLtK54TC6cuKnVzAY93ks4ZBrvwQSnkkIh7bsbNhum5hJBS00wSDipQ937f5DA==",
|
||||
"version": "2.7.16",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz",
|
||||
"integrity": "sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.18.4",
|
||||
"@babel/parser": "^7.23.5",
|
||||
"postcss": "^8.4.14",
|
||||
"source-map": "^0.6.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"prettier": "^1.18.2 || ^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/component-compiler-utils": {
|
||||
@@ -3307,7 +3311,6 @@
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -4904,6 +4907,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/decamelize": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/decamelize/-/decamelize-1.2.0.tgz",
|
||||
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/deep-is": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz",
|
||||
@@ -5147,6 +5158,11 @@
|
||||
"integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/dijkstrajs": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
|
||||
"integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA=="
|
||||
},
|
||||
"node_modules/dir-glob": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
@@ -5291,9 +5307,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/element-ui": {
|
||||
"version": "2.15.12",
|
||||
"resolved": "https://registry.npmjs.org/element-ui/-/element-ui-2.15.12.tgz",
|
||||
"integrity": "sha512-Y5FMT2BPOindU2GkDEQ5ZKUVxDawKONRNMh2eL3uBx1FOtvUJ+L6IxXLVsNxq4WnaX/UnVNgWXebl7DobygZMg==",
|
||||
"version": "2.15.14",
|
||||
"resolved": "https://registry.npmmirror.com/element-ui/-/element-ui-2.15.14.tgz",
|
||||
"integrity": "sha512-2v9fHL0ZGINotOlRIAJD5YuVB8V7WKxrE9Qy7dXhRipa035+kF7WuU/z+tEmLVPBcJ0zt8mOu1DKpWcVzBK8IA==",
|
||||
"dependencies": {
|
||||
"async-validator": "~1.8.1",
|
||||
"babel-helper-vue-jsx-merge-props": "^2.0.0",
|
||||
@@ -5309,8 +5325,7 @@
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"node_modules/emojis-list": {
|
||||
"version": "3.0.0",
|
||||
@@ -6385,7 +6400,6 @@
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/find-up/-/find-up-4.1.0.tgz",
|
||||
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"locate-path": "^5.0.0",
|
||||
"path-exists": "^4.0.0"
|
||||
@@ -6559,7 +6573,6 @@
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
@@ -7154,7 +7167,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -7567,7 +7579,6 @@
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz",
|
||||
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"p-locate": "^4.1.0"
|
||||
},
|
||||
@@ -7952,12 +7963,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.5.tgz",
|
||||
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"braces": "^3.0.2",
|
||||
"braces": "^3.0.3",
|
||||
"picomatch": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -8605,7 +8616,6 @@
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"p-try": "^2.0.0"
|
||||
},
|
||||
@@ -8617,7 +8627,6 @@
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-4.1.0.tgz",
|
||||
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"p-limit": "^2.2.0"
|
||||
},
|
||||
@@ -8654,7 +8663,6 @@
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/p-try/-/p-try-2.2.0.tgz",
|
||||
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@@ -8740,7 +8748,6 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz",
|
||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -8810,6 +8817,14 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/pngjs": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/pngjs/-/pngjs-5.0.0.tgz",
|
||||
"integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/portfinder": {
|
||||
"version": "1.0.32",
|
||||
"resolved": "https://registry.npmmirror.com/portfinder/-/portfinder-1.0.32.tgz",
|
||||
@@ -9393,7 +9408,6 @@
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmmirror.com/prettier/-/prettier-2.8.2.tgz",
|
||||
"integrity": "sha512-BtRV9BcncDyI2tsuS19zzhzoxD8Dh8LiCx7j7tHzrkz8GFXAexeWFdi22mjE1d16dftH2qNaytVxqiRTGlMfpw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"prettier": "bin-prettier.js"
|
||||
@@ -9502,6 +9516,121 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmmirror.com/qrcode/-/qrcode-1.5.4.tgz",
|
||||
"integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
|
||||
"dependencies": {
|
||||
"dijkstrajs": "^1.0.1",
|
||||
"pngjs": "^5.0.0",
|
||||
"yargs": "^15.3.1"
|
||||
},
|
||||
"bin": {
|
||||
"qrcode": "bin/qrcode"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode/node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode/node_modules/camelcase": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz",
|
||||
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode/node_modules/cliui": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/cliui/-/cliui-6.0.0.tgz",
|
||||
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^6.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode/node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode/node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/qrcode/node_modules/wrap-ansi": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
||||
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode/node_modules/y18n": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-4.0.3.tgz",
|
||||
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
|
||||
},
|
||||
"node_modules/qrcode/node_modules/yargs": {
|
||||
"version": "15.4.1",
|
||||
"resolved": "https://registry.npmmirror.com/yargs/-/yargs-15.4.1.tgz",
|
||||
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
|
||||
"dependencies": {
|
||||
"cliui": "^6.0.0",
|
||||
"decamelize": "^1.2.0",
|
||||
"find-up": "^4.1.0",
|
||||
"get-caller-file": "^2.0.1",
|
||||
"require-directory": "^2.1.1",
|
||||
"require-main-filename": "^2.0.0",
|
||||
"set-blocking": "^2.0.0",
|
||||
"string-width": "^4.2.0",
|
||||
"which-module": "^2.0.0",
|
||||
"y18n": "^4.0.0",
|
||||
"yargs-parser": "^18.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode/node_modules/yargs-parser": {
|
||||
"version": "18.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-18.1.3.tgz",
|
||||
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
|
||||
"dependencies": {
|
||||
"camelcase": "^5.0.0",
|
||||
"decamelize": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||
@@ -9771,7 +9900,6 @@
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -9785,6 +9913,11 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/require-main-filename": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
|
||||
},
|
||||
"node_modules/requires-port": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/requires-port/-/requires-port-1.0.0.tgz",
|
||||
@@ -10086,6 +10219,11 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
|
||||
},
|
||||
"node_modules/set-function-length": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
||||
@@ -10397,7 +10535,6 @@
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
@@ -10411,7 +10548,6 @@
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
@@ -10800,7 +10936,6 @@
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
"integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
@@ -11052,11 +11187,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "2.7.14",
|
||||
"resolved": "https://registry.npmmirror.com/vue/-/vue-2.7.14.tgz",
|
||||
"integrity": "sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==",
|
||||
"version": "2.7.16",
|
||||
"resolved": "https://registry.npmmirror.com/vue/-/vue-2.7.16.tgz",
|
||||
"integrity": "sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==",
|
||||
"deprecated": "Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.",
|
||||
"dependencies": {
|
||||
"@vue/compiler-sfc": "2.7.14",
|
||||
"@vue/compiler-sfc": "2.7.16",
|
||||
"csstype": "^3.1.0"
|
||||
}
|
||||
},
|
||||
@@ -11301,9 +11437,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/vue-template-compiler": {
|
||||
"version": "2.7.14",
|
||||
"resolved": "https://registry.npmmirror.com/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz",
|
||||
"integrity": "sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==",
|
||||
"version": "2.7.16",
|
||||
"resolved": "https://registry.npmmirror.com/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz",
|
||||
"integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"de-indent": "^1.0.2",
|
||||
@@ -11790,6 +11926,11 @@
|
||||
"which": "bin/which"
|
||||
}
|
||||
},
|
||||
"node_modules/which-module": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/which-module/-/which-module-2.0.1.tgz",
|
||||
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="
|
||||
},
|
||||
"node_modules/wildcard": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/wildcard/-/wildcard-2.0.0.tgz",
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
"dependencies": {
|
||||
"axios": "^1.7.4",
|
||||
"core-js": "^3.8.3",
|
||||
"element-ui": "^2.15.12",
|
||||
"vue": "^2.6.14",
|
||||
"element-ui": "^2.15.14",
|
||||
"qrcode": "^1.5.4",
|
||||
"vue": "^2.7.16",
|
||||
"vue-clipboard2": "^0.3.3",
|
||||
"vue-json-viewer": "^2.2.22"
|
||||
},
|
||||
@@ -21,12 +22,11 @@
|
||||
"@vue/cli-plugin-babel": "~5.0.0",
|
||||
"@vue/cli-plugin-eslint": "~5.0.0",
|
||||
"@vue/cli-service": "~5.0.0",
|
||||
"compression-webpack-plugin": "^6.1.1",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-plugin-vue": "^8.0.3",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
|
||||
"compression-webpack-plugin": "^6.1.1",
|
||||
"filemanager-webpack-plugin": "8.0.0"
|
||||
"filemanager-webpack-plugin": "8.0.0",
|
||||
"vue-template-compiler": "^2.7.16"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 KiB |
BIN
web-front/public/images/lanzou111.png
Normal file
BIN
web-front/public/images/lanzou111.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 69 KiB |
@@ -9,10 +9,6 @@
|
||||
content="Netdisk fast download,网盘直链解析工具">
|
||||
<meta name="description"
|
||||
content="Netdisk fast download 网盘直链解析工具">
|
||||
<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 async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9851170484804006"
|
||||
crossorigin="anonymous"></script>
|
||||
<style>
|
||||
.page-loading-wrap {
|
||||
padding: 120px;
|
||||
|
||||
@@ -4,18 +4,29 @@
|
||||
<el-card class="box-card">
|
||||
<div class="demo-basic--circle">
|
||||
<div class="block" style="text-align: center;">
|
||||
<el-avatar :size="150" :src="avatar"></el-avatar>
|
||||
<img :height="150" src="../public/images/lanzou111.png" alt="lz"></img>
|
||||
</div>
|
||||
</div>
|
||||
<h3 style="text-align: center;">NFD网盘直链解析0.1.8_bate(API演示)</h3>
|
||||
<h3 style="text-align: center;">NFD网盘直链解析0.1.8_bate2(API演示)</h3>
|
||||
<div class="typo">
|
||||
<p><strong>项目GitHub </strong><a href="https://github.com/qaiu/netdisk-fast-download" target="_blank"
|
||||
rel="nofollow"><u>netdisk-fast-download</u></a></p>
|
||||
<p style="text-align: center;">
|
||||
<span>
|
||||
<el-link href="https://github.com/qaiu/netdisk-fast-download" target="_blank" rel="nofollow">
|
||||
<u>GitHub</u></el-link>
|
||||
</span>
|
||||
<span style="margin-left: 30px">
|
||||
<el-link href="https://blog.qaiu.top/archives/netdisk-fast-download-bao-ta-an-zhuang-jiao-cheng" target="_blank"
|
||||
rel="nofollow"><u>宝塔部署安装教程</u>
|
||||
</el-link>
|
||||
</span>
|
||||
<span style="margin-left: 30px">
|
||||
<el-link href="https://blog.qaiu.top" target="_blank"
|
||||
rel="nofollow"><u>QAIU博客</u>
|
||||
</el-link>
|
||||
</span></p>
|
||||
<p><strong>目前支持 </strong>蓝奏云/蓝奏云优享/小飞机盘/123云盘/奶牛快传/移动云云空间/亿方云/文叔叔/QQ邮箱文件中转站</p>
|
||||
<p>已加入缓存机制, 如果遇到解析出的下载链接失效的情况请及时到项目GitHub反馈</p>
|
||||
<p>
|
||||
<el-button><strong @click="getInfo">刷新API调用统计</strong></el-button>
|
||||
</p>
|
||||
<p>已加入缓存机制, 如果遇到解析出的下载链接失效的情况请及时到<a href="https://github.com/qaiu/netdisk-fast-download/issues">
|
||||
<u><strong>项目GitHub反馈</strong></u></a></p>
|
||||
<p>节点1: 回源请求数:{{ node1Info.parserTotal }}, 缓存请求数:{{ node1Info.cacheTotal }}, 总数:{{ node1Info.total }}</p>
|
||||
<!-- <p>节点2: 成功:{{ node2Info.success }},失败:{{ node2Info.fail }},总数:{{ node2Info.total }}</p>-->
|
||||
</div>
|
||||
@@ -24,17 +35,24 @@
|
||||
<div class="grid-content">
|
||||
<el-input placeholder="请粘贴分享链接" v-model="link" id="url" lass="input-with-select">
|
||||
<strong slot="prepend">分享链接</strong>
|
||||
<el-button slot="append" @click="onSubmit">解析</el-button>
|
||||
</el-input>
|
||||
<el-input placeholder="请输入密码" v-model="password" id="url" lass="input-with-select"></el-input>
|
||||
<el-input placeholder="请输入密码" v-model="password" id="url" lass="input-with-select">
|
||||
<strong slot="prepend">分享密码</strong>
|
||||
</el-input>
|
||||
<el-input v-show="respData.data" placeholder="解析地址" :value="getLink2" id="url" lass="input-with-select">
|
||||
<el-button slot="append" v-clipboard:copy="getLink2"
|
||||
v-clipboard:success="onCopy"
|
||||
v-clipboard:error="onError">点我复制
|
||||
</el-button>
|
||||
</el-input>
|
||||
<p style="text-align: center">
|
||||
<el-button style="" @click="onSubmit">解析测试</el-button>
|
||||
<el-button style="margin-left: 20px" @click="genMd">生成Markdown链接</el-button>
|
||||
<el-button style="margin-left: 20px" @click="generateQRCode">生成二维码</el-button>
|
||||
<el-button style="margin-left: 20px" @click="getTj">链接信息统计</el-button>
|
||||
</p>
|
||||
</div>
|
||||
<div v-show="respData.code" style="margin-top: 10px">
|
||||
<div v-if="respData.code" style="margin-top: 10px">
|
||||
<strong>解析结果: </strong>
|
||||
<json-viewer
|
||||
:value="respData"
|
||||
@@ -45,6 +63,44 @@
|
||||
/>
|
||||
<a :href="downUrl" v-show="downUrl">点击下载</a>
|
||||
</div>
|
||||
<el-row v-if="mdText" style="text-align: center">
|
||||
<el-col span="22">
|
||||
<el-input
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 4, maxRows: 8}"
|
||||
placeholder="请输入内容"
|
||||
v-model="mdText">
|
||||
</el-input>
|
||||
</el-col>
|
||||
<el-col span="2">
|
||||
<el-button v-clipboard:copy="mdText"
|
||||
v-clipboard:success="onCopy"
|
||||
v-clipboard:error="onError">复制
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div style="text-align: center" v-show="showQrc">
|
||||
<div style="text-align: center"><el-link target="_blank" :href="codeUrl">{{ codeUrl }}</el-link></div>
|
||||
<canvas ref="qrcodeCanvas"></canvas>
|
||||
<div style="text-align: center"> 扫码下载 </div>
|
||||
</div>
|
||||
<div v-if="tjData.shareLinkInfo">
|
||||
<el-descriptions class="margin-top" title="分享详情" :column="1" border>
|
||||
<template slot="extra">
|
||||
<el-button type="primary" size="small">操作</el-button>
|
||||
</template>
|
||||
<el-descriptions-item label="网盘名称">{{ tjData.shareLinkInfo.panName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="网盘标识">{{ tjData.shareLinkInfo.type }}</el-descriptions-item>
|
||||
<el-descriptions-item label="分享Key">{{ tjData.shareLinkInfo.shareKey }}</el-descriptions-item>
|
||||
<el-descriptions-item label="分享链接"> <el-link target="_blank" :href="tjData.shareLinkInfo.shareUrl">{{ tjData.shareLinkInfo.shareUrl }}</el-link></el-descriptions-item>
|
||||
<el-descriptions-item label="jsonApi链接"> <el-link target="_blank" :href="tjData.apiLink">{{ tjData.apiLink }}</el-link></el-descriptions-item>
|
||||
<el-descriptions-item label="302下载链接"> <el-link target="_blank" :href="tjData.downLink">{{ tjData.downLink }}</el-link></el-descriptions-item>
|
||||
<el-descriptions-item label="解析次数">{{ tjData.parserTotal }}</el-descriptions-item>
|
||||
<el-descriptions-item label="缓存命中次数">{{ tjData.cacheHitTotal }}</el-descriptions-item>
|
||||
<el-descriptions-item label="总请求次数">{{ tjData.sumTotal }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</el-card>
|
||||
</el-row>
|
||||
@@ -53,6 +109,7 @@
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import QRCode from 'qrcode'
|
||||
/*
|
||||
蓝奏云 (lz)
|
||||
登录, 上传, 下载, 分享
|
||||
@@ -79,13 +136,19 @@ export default {
|
||||
name: 'App',
|
||||
data() {
|
||||
return {
|
||||
// baseAPI: `${location.protocol}//${location.hostname}:6400`,
|
||||
baseAPI: `${location.protocol}//${location.host}`,
|
||||
current: {}, // 当前分享
|
||||
showQrc: false,
|
||||
codeUrl: '',
|
||||
mdText: '',
|
||||
link: "",
|
||||
password: "",
|
||||
isLoading: false,
|
||||
downUrl: null,
|
||||
avatar: "https://q2.qlogo.cn/headimg_dl?dst_uin=736226400&spec=640",
|
||||
select: "lz",
|
||||
respData: {},
|
||||
tjData: {},
|
||||
panList: [
|
||||
{
|
||||
name: "蓝奏云",
|
||||
@@ -117,28 +180,36 @@ export default {
|
||||
value: 'ye'
|
||||
},
|
||||
],
|
||||
getLink: '',
|
||||
getLink: null,
|
||||
getLink2: '',
|
||||
getLinkInfo: null,
|
||||
node1Info: {},
|
||||
node2Info: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onSubmit() {
|
||||
check() {
|
||||
this.mdText = ''
|
||||
this.showQrc = false
|
||||
this.respData = {}
|
||||
this.tjData = {}
|
||||
if (!this.link.startsWith("https://")) {
|
||||
this.$message.error("请输入有效链接!")
|
||||
return
|
||||
throw new Error('请输入有效链接')
|
||||
}
|
||||
},
|
||||
onSubmit() {
|
||||
this.check()
|
||||
this.isLoading = true
|
||||
this.downUrl = ''
|
||||
this.respData = {}
|
||||
this.getLink2 = `${location.protocol}//${location.host}/parser?url=${this.link}`
|
||||
this.getLink2 = `${this.baseAPI}/parser?url=${this.link}`
|
||||
// this.getLink = `${location.protocol}//${location.host}/api/json/parser?url=${this.link}`
|
||||
this.getLink = `${location.protocol}//${location.host}/json/parser?url=${this.link}`
|
||||
// this.getLink = `${location.protocol}//${location.host}/json/parser`
|
||||
if (this.password) {
|
||||
this.getLink += `&pwd=${this.password}`
|
||||
this.getLink2 += `&pwd=${this.password}`
|
||||
}
|
||||
axios.get(this.getLink).then(
|
||||
axios.get(this.getLink, {params: {url: this.link, pwd: this.password}}).then(
|
||||
response => {
|
||||
this.isLoading = false
|
||||
this.respData = response.data
|
||||
@@ -179,9 +250,73 @@ export default {
|
||||
// this.node2Info = response.data.data
|
||||
// }
|
||||
// })
|
||||
},
|
||||
genMd() {
|
||||
this.check()
|
||||
axios.get(this.getLinkInfo, {params: {url: this.link, pwd: this.password}}).then(
|
||||
response => {
|
||||
this.isLoading = false
|
||||
if (response.data.code === 200) {
|
||||
this.$message({
|
||||
message: response.data.msg,
|
||||
type: 'success'
|
||||
})
|
||||
this.mdText = this.buildMd('快速下载地址',response.data.data.downLink)
|
||||
} else {
|
||||
this.$message.error(response.data.msg)
|
||||
}
|
||||
});
|
||||
},
|
||||
buildMd(title, url) {
|
||||
return `[${title}](${url})`
|
||||
},
|
||||
generateQRCode() {
|
||||
this.check()
|
||||
const options = { // 设置二维码的参数,例如大小、边距等
|
||||
width: 150,
|
||||
height: 150,
|
||||
margin: 2,
|
||||
colorDark : "#8e0fb7",
|
||||
colorLight : "#fff2ad",
|
||||
};
|
||||
axios.get(this.getLinkInfo, {params: {url: this.link, pwd: this.password}}).then(
|
||||
response => {
|
||||
this.isLoading = false
|
||||
if (response.data.code === 200) {
|
||||
this.$message({
|
||||
message: response.data.msg,
|
||||
type: 'success'
|
||||
})
|
||||
this.codeUrl = response.data.data.downLink
|
||||
QRCode.toCanvas(this.$refs.qrcodeCanvas, this.codeUrl, options, error => {
|
||||
if (error) console.error(error);
|
||||
});
|
||||
this.showQrc = true
|
||||
} else {
|
||||
this.$message.error(response.data.msg)
|
||||
}
|
||||
});
|
||||
},
|
||||
getTj() {
|
||||
this.check()
|
||||
axios.get(this.getLinkInfo, {params: {url: this.link, pwd: this.password}}).then(
|
||||
response => {
|
||||
this.isLoading = false
|
||||
if (response.data.code === 200) {
|
||||
this.$message({
|
||||
message: response.data.msg,
|
||||
type: 'success'
|
||||
})
|
||||
this.tjData = response.data.data
|
||||
} else {
|
||||
this.$message.error(response.data.msg)
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getLinkInfo = `${this.baseAPI}/v2/linkInfo`
|
||||
this.getLink = `${this.baseAPI}/json/parser`
|
||||
this.getInfo()
|
||||
}
|
||||
}
|
||||
@@ -255,8 +390,7 @@ body:before {
|
||||
}
|
||||
|
||||
.typo a {
|
||||
color: #2c3e50;
|
||||
text-decoration: none;
|
||||
color: #0077ff;
|
||||
}
|
||||
|
||||
hr {
|
||||
|
||||
10662
web-front/yarn.lock
10662
web-front/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -51,7 +51,7 @@ public class CacheManager {
|
||||
.mapEmpty();
|
||||
}
|
||||
|
||||
// 统计网盘厂商API解析次数
|
||||
// 写入网盘厂商API解析次数
|
||||
public Future<Integer> updateTotalByCached(String shareKey) {
|
||||
Promise<Integer> promise = Promise.promise();
|
||||
String sql = """
|
||||
@@ -81,7 +81,7 @@ public class CacheManager {
|
||||
return fullShareKey.split(":")[0];
|
||||
}
|
||||
|
||||
// 统计网盘厂商API解析次数
|
||||
// 写入网盘厂商API解析次数
|
||||
public Future<Integer> updateTotalByParser(String shareKey) {
|
||||
Promise<Integer> promise = Promise.promise();
|
||||
String sql = """
|
||||
@@ -125,5 +125,31 @@ public class CacheManager {
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
public Future<Map<String, Integer>> getShareKeyTotal(String shareKey) {
|
||||
String sql = """
|
||||
select `share_key`, sum(cache_hit_total) hit_total, sum(api_parser_total) parser_total,
|
||||
from `api_statistics_info`
|
||||
group by `share_key` having `share_key` = #{shareKey}
|
||||
""";
|
||||
Promise<Map<String, 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 -> {
|
||||
if(res.iterator().hasNext()) {
|
||||
JsonObject next = res.iterator().next();
|
||||
Map<String, Integer> resp = new HashMap<>(){{
|
||||
put("hit_total" ,next.getInteger("hit_total"));
|
||||
put("parser_total" ,next.getInteger("parser_total"));
|
||||
}};
|
||||
promise.complete(resp);
|
||||
} else {
|
||||
promise.complete();
|
||||
}
|
||||
});
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package cn.qaiu.lz.web.controller;
|
||||
|
||||
|
||||
import cn.qaiu.entity.ShareLinkInfo;
|
||||
import cn.qaiu.lz.common.cache.CacheManager;
|
||||
import cn.qaiu.lz.common.util.URLParamUtil;
|
||||
import cn.qaiu.lz.web.model.LinkInfoResp;
|
||||
import cn.qaiu.lz.web.model.SysUser;
|
||||
import cn.qaiu.lz.web.service.DbService;
|
||||
import cn.qaiu.lz.web.service.UserService;
|
||||
import cn.qaiu.lz.web.model.StatisticsInfo;
|
||||
import cn.qaiu.parser.ParserCreate;
|
||||
import cn.qaiu.vx.core.annotaions.RouteHandler;
|
||||
import cn.qaiu.vx.core.annotaions.RouteMapping;
|
||||
import cn.qaiu.vx.core.enums.RouteMethod;
|
||||
import cn.qaiu.vx.core.util.AsyncServiceUtil;
|
||||
import cn.qaiu.vx.core.util.SharedDataUtil;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.http.HttpServerRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@RouteHandler(value = "/v2", order = 10)
|
||||
@Slf4j
|
||||
public class ParserApi {
|
||||
|
||||
private final UserService userService = AsyncServiceUtil.getAsyncServiceInstance(UserService.class);
|
||||
private final DbService dbService = AsyncServiceUtil.getAsyncServiceInstance(DbService.class);
|
||||
|
||||
@RouteMapping(value = "/login", method = RouteMethod.POST)
|
||||
public Future<SysUser> login(SysUser user) {
|
||||
log.info("<------- login: {}", user.getUsername());
|
||||
return userService.login(user);
|
||||
}
|
||||
|
||||
@RouteMapping(value = "/statisticsInfo", method = RouteMethod.GET, order = 99)
|
||||
public Future<StatisticsInfo> statisticsInfo() {
|
||||
return dbService.getStatisticsInfo();
|
||||
}
|
||||
|
||||
private final CacheManager cacheManager = new CacheManager();
|
||||
|
||||
@RouteMapping(value = "/linkInfo", method = RouteMethod.GET)
|
||||
public Future<LinkInfoResp> parse(HttpServerRequest request, String pwd) {
|
||||
Promise<LinkInfoResp> promise = Promise.promise();
|
||||
String url = URLParamUtil.parserParams(request);
|
||||
ParserCreate parserCreate = ParserCreate.fromShareUrl(url).setShareLinkInfoPwd(pwd);
|
||||
ShareLinkInfo shareLinkInfo = parserCreate.getShareLinkInfo();
|
||||
LinkInfoResp build = LinkInfoResp.builder()
|
||||
.downLink(getDownLink(parserCreate, false))
|
||||
.apiLink(getDownLink(parserCreate, true))
|
||||
.shareLinkInfo(shareLinkInfo).build();
|
||||
// 解析次数统计
|
||||
cacheManager.getShareKeyTotal(shareLinkInfo.getCacheKey()).onSuccess(res -> {
|
||||
if (res != null) {
|
||||
build.setCacheHitTotal(res.get("hit_total") == null ? 0: res.get("hit_total"));
|
||||
build.setParserTotal(res.get("parser_total") == null ? 0: res.get("parser_total"));
|
||||
build.setSumTotal(build.getCacheHitTotal() + build.getParserTotal());
|
||||
}
|
||||
promise.complete(build);
|
||||
}).onFailure(t->{
|
||||
t.printStackTrace();
|
||||
promise.complete(build);
|
||||
});
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
private static String getDownLink(ParserCreate create, boolean isJson) {
|
||||
|
||||
String linkPrefix = SharedDataUtil.getJsonConfig("server")
|
||||
.getString("domainName");
|
||||
if (StringUtils.isBlank(linkPrefix)) {
|
||||
linkPrefix = "http://127.0.0.1";
|
||||
}
|
||||
return linkPrefix + (isJson ? "/json/" : "/") + create.genPathSuffix();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.qaiu.lz.web.http;
|
||||
package cn.qaiu.lz.web.controller;
|
||||
|
||||
import cn.qaiu.lz.common.util.URLParamUtil;
|
||||
import cn.qaiu.lz.web.model.CacheLinkInfo;
|
||||
@@ -26,7 +26,7 @@ public class ServerApi {
|
||||
|
||||
private final CacheService cacheService = AsyncServiceUtil.getAsyncServiceInstance(CacheService.class);
|
||||
|
||||
@RouteMapping(value = "/parser", method = RouteMethod.GET, order = 4)
|
||||
@RouteMapping(value = "/parser", method = RouteMethod.GET, order = 1)
|
||||
public Future<Void> parse(HttpServerResponse response, HttpServerRequest request, String pwd) {
|
||||
Promise<Void> promise = Promise.promise();
|
||||
String url = URLParamUtil.parserParams(request);
|
||||
@@ -40,13 +40,13 @@ public class ServerApi {
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
@RouteMapping(value = "/json/parser", method = RouteMethod.GET, order = 3)
|
||||
@RouteMapping(value = "/json/parser", method = RouteMethod.GET, order = 1)
|
||||
public Future<CacheLinkInfo> parseJson(HttpServerRequest request, String pwd) {
|
||||
String url = URLParamUtil.parserParams(request);
|
||||
return cacheService.getCachedByShareUrlAndPwd(url, pwd);
|
||||
}
|
||||
|
||||
@RouteMapping(value = "/json/:type/:key", method = RouteMethod.GET, order = 2)
|
||||
@RouteMapping(value = "/json/:type/:key", method = RouteMethod.GET)
|
||||
public Future<CacheLinkInfo> parseKeyJson(String type, String key) {
|
||||
String pwd = "";
|
||||
if (key.contains("@")) {
|
||||
@@ -57,7 +57,7 @@ public class ServerApi {
|
||||
return cacheService.getCachedByShareKeyAndPwd(type, key, pwd);
|
||||
}
|
||||
|
||||
@RouteMapping(value = "/:type/:key", method = RouteMethod.GET, order = 1)
|
||||
@RouteMapping(value = "/:type/:key", method = RouteMethod.GET)
|
||||
public Future<Void> parseKey(HttpServerResponse response, String type, String key) {
|
||||
Promise<Void> promise = Promise.promise();
|
||||
String pwd = "";
|
||||
@@ -1,32 +0,0 @@
|
||||
package cn.qaiu.lz.web.http;
|
||||
|
||||
|
||||
import cn.qaiu.lz.web.model.SysUser;
|
||||
import cn.qaiu.lz.web.service.DbService;
|
||||
import cn.qaiu.lz.web.service.UserService;
|
||||
import cn.qaiu.lz.web.model.StatisticsInfo;
|
||||
import cn.qaiu.vx.core.annotaions.RouteHandler;
|
||||
import cn.qaiu.vx.core.annotaions.RouteMapping;
|
||||
import cn.qaiu.vx.core.enums.RouteMethod;
|
||||
import cn.qaiu.vx.core.util.AsyncServiceUtil;
|
||||
import io.vertx.core.Future;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@RouteHandler(value = "/v2", order = 10)
|
||||
@Slf4j
|
||||
public class ParserApi {
|
||||
|
||||
private final UserService userService = AsyncServiceUtil.getAsyncServiceInstance(UserService.class);
|
||||
private final DbService dbService = AsyncServiceUtil.getAsyncServiceInstance(DbService.class);
|
||||
|
||||
@RouteMapping(value = "/login", method = RouteMethod.POST)
|
||||
public Future<SysUser> login(SysUser user) {
|
||||
log.info("<------- login: {}", user.getUsername());
|
||||
return userService.login(user);
|
||||
}
|
||||
|
||||
@RouteMapping(value = "/statisticsInfo", method = RouteMethod.GET, order = 99)
|
||||
public Future<StatisticsInfo> statisticsInfo() {
|
||||
return dbService.getStatisticsInfo();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package cn.qaiu.lz.web.model;
|
||||
|
||||
import cn.qaiu.entity.ShareLinkInfo;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class LinkInfoResp {
|
||||
// 解析链接
|
||||
private String downLink;
|
||||
private String apiLink;
|
||||
private Integer cacheHitTotal;
|
||||
private Integer parserTotal;
|
||||
private Integer sumTotal;
|
||||
private ShareLinkInfo shareLinkInfo;
|
||||
}
|
||||
@@ -23,8 +23,8 @@ public class CacheServiceImpl implements CacheService {
|
||||
Promise<CacheLinkInfo> promise = Promise.promise();
|
||||
// 构建组合的缓存key
|
||||
ShareLinkInfo shareLinkInfo = parserCreate.getShareLinkInfo();
|
||||
String cacheKey = generateCacheKey(shareLinkInfo.getType(), shareLinkInfo.getShareKey());
|
||||
// 尝试从缓存中获取
|
||||
String cacheKey = shareLinkInfo.getCacheKey();
|
||||
cacheManager.get(cacheKey).onSuccess(result -> {
|
||||
// 判断是否已过期
|
||||
// 未命中或者过期
|
||||
@@ -57,11 +57,6 @@ public class CacheServiceImpl implements CacheService {
|
||||
return promise.future();
|
||||
}
|
||||
|
||||
private String generateCacheKey(String type, String shareKey) {
|
||||
// 将type和shareKey组合成一个字符串作为缓存key
|
||||
return type + ":" + shareKey;
|
||||
}
|
||||
|
||||
private String generateDate(Long ts) {
|
||||
return DateFormatUtils.format(new Date(ts), "yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
server:
|
||||
port: 6400
|
||||
contextPath: /
|
||||
# 使用静态页面
|
||||
enableStaticHtmlService: false
|
||||
# 使用数据库
|
||||
enableDatabase: true
|
||||
staticResourcePath: webroot/
|
||||
# 服务域名或者IP 生成二维码链接时需要
|
||||
domainName: https://lz.qaiu.top
|
||||
|
||||
# 反向代理服务器配置路径(不用加后缀)
|
||||
proxyConf: server-proxy
|
||||
|
||||
# vertx线程配置 事件循环线程配置为0: eventLoopPoolSize将会采用默认配置(CPU核心*2) workerPoolSize将会采用默认20
|
||||
# vertx线程配置, 为0表示eventLoopPoolSize将会采用默认配置(CPU核心*2) workerPoolSize将会采用默认20
|
||||
vertx:
|
||||
eventLoopPoolSize: 0
|
||||
workerPoolSize: 0
|
||||
@@ -50,8 +50,8 @@ cache:
|
||||
cow:
|
||||
ec:
|
||||
fc:
|
||||
fj:
|
||||
iz:
|
||||
fj: 30
|
||||
iz: 20
|
||||
le: 2879
|
||||
lz:
|
||||
qq: 999999
|
||||
|
||||
66
web-service/src/main/resources/http-tools/temp.http
Normal file
66
web-service/src/main/resources/http-tools/temp.http
Normal file
@@ -0,0 +1,66 @@
|
||||
# curl 'https://ip.ihuan.me/tqdl.html'
|
||||
# -H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'
|
||||
# -H 'accept-language: zh-CN,zh;q=0.9,en;q=0.8'
|
||||
# -H 'cache-control: no-cache'
|
||||
# -H 'content-type: application/x-www-form-urlencoded'
|
||||
# -H 'cookie: 91e73cee101cc3ecefd9ca31a227d508=4380c9f80effb56e85210a54dc286c06; statistics=16453d6e2683b8800ded2a27c7f595d9; Hm_lvt_8ccd0ef22095c2eebfe4cd6187dea829=1727664099; HMACCOUNT=AA7CAD3BA9E39EC8; 28114211b4e11617bd725475433e69aa=29d9778b3f2c1b30c137fef0d6728e29; Hm_lpvt_8ccd0ef22095c2eebfe4cd6187dea829=1727667138'
|
||||
# -H 'dnt: 1'
|
||||
# -H 'origin: https://ip.ihuan.me'
|
||||
# -H 'pragma: no-cache'
|
||||
# -H 'priority: u=0, i'
|
||||
# -H 'referer: https://ip.ihuan.me/ti.html'
|
||||
# -H 'sec-ch-ua: "Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"'
|
||||
# -H 'sec-ch-ua-mobile: ?0'
|
||||
# -H 'sec-ch-ua-platform: "Windows"'
|
||||
# -H 'sec-fetch-dest: document'
|
||||
# -H 'sec-fetch-mode: navigate'
|
||||
# -H 'sec-fetch-site: same-origin'
|
||||
# -H 'sec-fetch-user: ?1'
|
||||
# -H 'upgrade-insecure-requests: 1'
|
||||
# -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36'
|
||||
# --data-raw 'num=100&port=&kill_port=&address=&kill_address=&anonymity=&type=&post=&sort=&key=15146aca2e04e3756a2e79ec33ca5679'
|
||||
#@no-cookie-jar
|
||||
POST https://ip.ihuan.me/tqdl.html
|
||||
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
|
||||
accept-language: zh-CN,zh;q=0.9,en;q=0.8
|
||||
cache-control: no-cache
|
||||
cookie: 91e73cee101cc3ecefd9ca31a227d508=4380c9f80effb56e85210a54dc286c06; statistics=16453d6e2683b8800ded2a27c7f595d9; Hm_lvt_8ccd0ef22095c2eebfe4cd6187dea829=1727664099; HMACCOUNT=AA7CAD3BA9E39EC8; 28114211b4e11617bd725475433e69aa=29d9778b3f2c1b30c137fef0d6728e29; Hm_lpvt_8ccd0ef22095c2eebfe4cd6187dea829=1727667138
|
||||
dnt: 1
|
||||
origin: https://ip.ihuan.me
|
||||
pragma: no-cache
|
||||
priority: u=0, i
|
||||
referer: https://ip.ihuan.me/ti.html
|
||||
sec-ch-ua: "Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"
|
||||
sec-ch-ua-mobile: ?0
|
||||
sec-ch-ua-platform: "Windows"
|
||||
sec-fetch-dest: document
|
||||
sec-fetch-mode: navigate
|
||||
sec-fetch-site: same-origin
|
||||
sec-fetch-user: ?1
|
||||
upgrade-insecure-requests: 1
|
||||
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
num=100&port=&kill_port=&address=&kill_address=&anonymity=&type=&post=&sort=&key=15146aca2e04e3756a2e79ec33ca5679
|
||||
|
||||
###
|
||||
https://ip.ihuan.me/
|
||||
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
|
||||
accept-language: zh-CN,zh;q=0.9,en;q=0.8
|
||||
cache-control: no-cache
|
||||
#cookie: 91e73cee101cc3ecefd9ca31a227d508=4380c9f80effb56e85210a54dc286c06; statistics=16453d6e2683b8800ded2a27c7f595d9; Hm_lvt_8ccd0ef22095c2eebfe4cd6187dea829=1727664099; HMACCOUNT=AA7CAD3BA9E39EC8; 28114211b4e11617bd725475433e69aa=29d9778b3f2c1b30c137fef0d6728e29; Hm_lpvt_8ccd0ef22095c2eebfe4cd6187dea829=1727667138
|
||||
dnt: 1
|
||||
origin: https://ip.ihuan.me
|
||||
pragma: no-cache
|
||||
priority: u=0, i
|
||||
referer: https://ip.ihuan.me
|
||||
sec-ch-ua: "Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"
|
||||
sec-ch-ua-mobile: ?0
|
||||
sec-ch-ua-platform: "Windows"
|
||||
sec-fetch-dest: document
|
||||
sec-fetch-mode: navigate
|
||||
sec-fetch-site: same-origin
|
||||
sec-fetch-user: ?1
|
||||
upgrade-insecure-requests: 1
|
||||
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
@@ -1,6 +1,6 @@
|
||||
### PASS 蓝奏云
|
||||
# @no-redirect
|
||||
GET http://127.0.0.1:6400/parser?url=https://www.lanzoux.com/ia2cntg
|
||||
GET http://127.0.0.1:6400/parser?url=https://www123-asd111.lanzoux.com/ia2cntg
|
||||
|
||||
### 蓝奏云
|
||||
# @no-redirect
|
||||
@@ -111,6 +111,9 @@ GET http://127.0.0.1:6400/ye/Ev1lVv-t3SY3
|
||||
# @no-redirect
|
||||
GET http://127.0.0.1:6400/json/parser?url=https://www.123pan.com/s/iaKtVv-6OECd.html&pwd=DcGe
|
||||
|
||||
### 123 PASS https://www.123865.com/s/iaKtVv-6OECd.html
|
||||
# @no-redirect
|
||||
GET http://127.0.0.1:6400/json/parser?url=https://www.123865.com/s/iaKtVv-6OECd.html&pwd=DcGe
|
||||
|
||||
### 123
|
||||
# @no-redirect
|
||||
@@ -133,15 +136,26 @@ GET http://127.0.0.1:6400/le/2RkKbLP9BrppS9b43@ex2b
|
||||
GET http://127.0.0.1:6400/json/le/2RkKbLP9BrppS9b43@ex2b
|
||||
|
||||
### PASS 文叔叔
|
||||
GET http://127.0.0.1:6400/parser?url=https://f.ws59.cn/f/f25625rv6p6
|
||||
GET http://127.0.0.1:6400/json/parser?url=https://f.ws28.cn/f/f5wtc2iwxtk
|
||||
###
|
||||
https://f.wss.cc/f/f25625rv6p6
|
||||
|
||||
### TODO Cloudreve
|
||||
GET http://127.0.0.1:6400/json/ce/https_pan.huang1111.cn_s_wDz5TK
|
||||
GET http://127.0.0.1:6400/json/ce/pan.huang1111.cn_s_wDz5TK
|
||||
|
||||
### Cloudreve2
|
||||
GET http://127.0.0.1:6400/json/ce/pan.huang1111.cn_s_g31PcQ@qaiu
|
||||
|
||||
### Cloudreve类 PASS
|
||||
### https://pan.huang1111.cn/s/g31PcQ
|
||||
### 看见存储 https://pan.seeoss.com/s/nLNsQ
|
||||
### 亿安云盘 https://dav.yiandrive.com/s/xxx
|
||||
#GET http://127.0.0.1:6400/parser?url=https://pan.huang1111.cn/s/g31PcQ&pwd=qaiu
|
||||
|
||||
# @no-redirect
|
||||
GET http://127.0.0.1:6400/parser?url=https://pan.seeoss.com/s/nLNsQ
|
||||
|
||||
|
||||
### Cloudreve https://pan.huang1111.cn/s/g31PcQ
|
||||
GET http://127.0.0.1:6400/parser?url=https://pan.huang1111.cn/s/g31PcQ&pwd=qaiu
|
||||
|
||||
### PASS QQ
|
||||
# @no-redirect
|
||||
@@ -152,9 +166,30 @@ GET http://127.0.0.1:6400/json/parser?url=https://iwx.mail.qq.com/ftn/download?f
|
||||
###
|
||||
GET http://127.0.0.1:6400/v2/statisticsInfo
|
||||
|
||||
###
|
||||
GET http://127.0.0.1:6400/v2/linkInfo?url=https://www.123865.com/s/iaKtVv-6OECd.html&pwd=DcGe
|
||||
###
|
||||
GET http://127.0.0.1:6400/v2/linkInfo?url=https://pan.seeoss.com/s/nLNsQ&pwd=DcGe
|
||||
|
||||
###
|
||||
POST http://127.0.0.1:6400/v2/login?username=asd
|
||||
|
||||
|
||||
|
||||
### 6401/v2
|
||||
GET http://127.0.0.1:6401/v2/linkInfo?url=https://pan.seeoss.com/s/nLNsQ&pwd=DcGe
|
||||
|
||||
|
||||
|
||||
### PASS QQ
|
||||
# @no-redirect
|
||||
GET http://127.0.0.1:6401/parser?url=https://iwx.mail.qq.com/ftn/download?func=3&key=qweqe&code=8c02cf57&k=asdad
|
||||
|
||||
|
||||
### PASS QQ
|
||||
# @no-redirect
|
||||
GET http://127.0.0.1:6401/json/parser?url=https://iwx.mail.qq.com/ftn/download?func=3&key=qweqe&code=8c02cf57&k=asdad
|
||||
|
||||
### n1
|
||||
http://127.0.0.1:6401/n1/statisticsInfo
|
||||
|
||||
|
||||
@@ -1,22 +1,43 @@
|
||||
# 反向代理
|
||||
server-name: Vert.x-proxy-server(v4.1.2)
|
||||
|
||||
#proxy:
|
||||
# - listen: 8085
|
||||
# # 404的路径
|
||||
# 404: webroot/real-html/index.html
|
||||
# static:
|
||||
# path: /
|
||||
## add-headers:
|
||||
## x-token: ABC
|
||||
# root: webroot/real-html/
|
||||
# index: realIndex
|
||||
# location:
|
||||
# - path: /real/
|
||||
# origin: 127.0.0.1:8088
|
||||
# - path: /api/
|
||||
# origin: 127.0.0.1:7070/demo/
|
||||
#
|
||||
proxy:
|
||||
- listen: 6401
|
||||
# 404的路径
|
||||
page404: webroot/err/404.html
|
||||
static:
|
||||
path: /
|
||||
add-headers:
|
||||
x-token: ABC
|
||||
root: webroot/nfd-front/
|
||||
# index: index.html
|
||||
# ~开通表示正则匹配否则为前缀匹配, 当origin带子路径时进行路由重写,
|
||||
# 1.origin代理地址端口后有目录(包括 / ),转发后地址:代理地址+访问URL目录部分去除location匹配目录
|
||||
# 2.origin代理地址端口后无任何,转发后地址:代理地址+访问URL目录部
|
||||
location:
|
||||
- path: ~^/(json/|v2/|parser).*
|
||||
origin: 127.0.0.1:6400
|
||||
|
||||
# json/parser -> xxx/parser
|
||||
# - path: /json/
|
||||
# origin: 127.0.0.1:6400/
|
||||
- path: /n1/
|
||||
origin: 127.0.0.1:6400/v2/
|
||||
|
||||
# # SSL HTTPS配置
|
||||
ssl:
|
||||
enable: false
|
||||
# 强制https 暂不支持
|
||||
#ssl_force: true
|
||||
# SSL 协议版本
|
||||
ssl_protocols: TLSv1.2
|
||||
# 证书
|
||||
ssl_certificate: ssl/server.pem
|
||||
# 私钥
|
||||
ssl_certificate_key: ssl/privkey.key
|
||||
# 加密套件 ssl_ciphers 暂不支持
|
||||
# ssl_ciphers: AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
|
||||
|
||||
# - listen: 8086
|
||||
# static:
|
||||
# path: /t2/
|
||||
|
||||
15
web-service/src/main/resources/ssl/privkey.key
Normal file
15
web-service/src/main/resources/ssl/privkey.key
Normal file
@@ -0,0 +1,15 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXgIBAAKBgQDdpOpVrYhr6bMddEbbVXQebA24vMLJylHoOngN09Rx8KM/wJZz
|
||||
4zDPNJJumsQz/kyAX1pd70rxdNb4MLq/ToVlzKIct45y1HvzVzVZA78gP3OKfO9w
|
||||
JZ+d+MLLw8kmtL2PQSMi0HNHm5LsMyON5eScyBPCR0D2P0bydEiv3df7mwIDAQAB
|
||||
AoGAHDILgWS28wtitr+A+Avx3qDeSf7xRJxRORqfBRtKbkgvbD/Co/Fl1yYX7qwP
|
||||
g5G5B6eZplN3lCnJ4v7H8ug5PdJg3RuGmR4EYTx2k/nd/hGNRZfUgWHCII6BjGxN
|
||||
14n1BcZtDVPR8yvcUXKjlpCemMUQE1xzVLO2nEq/gJtEWpkCQQDzZ4hYjpV6Tsy+
|
||||
DN2oLqAtuyeudM2ZSN6ubnEr+OsBfNlHd38z8liCRztAQkBNgrfGqlng79j5fL/p
|
||||
s/8N5mcvAkEA6R0d/FFe4lBNSxPFrzW73mY2AK5ebuAuB3punkDuS5nkBW+1Jg9p
|
||||
j+ZZrqYv1ZNR7pAN5DkRBPV2c/y2n3WXVQJBAK0RlbIaGBDyTMRpk4YNORmrNKjo
|
||||
JnRyituObevtPvQ82KXnQswl6mcfzPKA6QX0B0Y8RFIbWLT0zeSXdqhkhkMCQQCR
|
||||
SdJ8hgKLLt1do48b6nOS40VZG1RD6nkFtCrpezKJ7/oL4VmXxRdX1ouirHU3ub/g
|
||||
3euqiF6xJoOTOrhfnhyZAkEAncfWxN1U969lkfNo7ECPJEP2RJzZVcb5PJYab1NL
|
||||
ccI6qxt/hwNk3NYYEWXavICowVVUNhn2MakeY9cXRlbs3w==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
13
web-service/src/main/resources/ssl/server.pem
Normal file
13
web-service/src/main/resources/ssl/server.pem
Normal file
@@ -0,0 +1,13 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIB9jCCAV8CFEC4MswPv8GgOAulmgIMioLiNn6GMA0GCSqGSIb3DQEBCwUAMDox
|
||||
CzAJBgNVBAYTAmNuMQ0wCwYDVQQIDARxYWl1MQ0wCwYDVQQHDARxYWl1MQ0wCwYD
|
||||
VQQKDARxYWl1MB4XDTI0MTAwMzIxMDM1MFoXDTM0MTAwMTIxMDM1MFowOjELMAkG
|
||||
A1UEBhMCY24xDTALBgNVBAgMBHFhaXUxDTALBgNVBAcMBHFhaXUxDTALBgNVBAoM
|
||||
BHFhaXUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAN2k6lWtiGvpsx10RttV
|
||||
dB5sDbi8wsnKUeg6eA3T1HHwoz/AlnPjMM80km6axDP+TIBfWl3vSvF01vgwur9O
|
||||
hWXMohy3jnLUe/NXNVkDvyA/c4p873Aln534wsvDySa0vY9BIyLQc0ebkuwzI43l
|
||||
5JzIE8JHQPY/RvJ0SK/d1/ubAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAOGALPb49
|
||||
rQWM2gctt4jZECtV9t8/eU5XArtNuf3ixKZVmg5LEOmSQ8v9Qs20l5KwIBxiyKIz
|
||||
GW7kip1lF5gp/sxuYHOSzVhhpbRZkQsANf7yUpAZtlHP4W4vgf+pdZ8DcF/az9KT
|
||||
Ne9Z+nkXdXoTp9E4PQqbgAteWFRcg5MjbsE=
|
||||
-----END CERTIFICATE-----
|
||||
71
web-service/src/main/resources/ssl/自签证书说明.md
Normal file
71
web-service/src/main/resources/ssl/自签证书说明.md
Normal file
@@ -0,0 +1,71 @@
|
||||
OpenSSL 证书
|
||||
|
||||
第一步:生成私钥
|
||||
|
||||
在使用 openssl 生成 SSL 证书之前,我们需要先生成私钥。可以使用如下命令行来生成私钥:
|
||||
|
||||
```
|
||||
|
||||
openssl genrsa -out key.pem 1024
|
||||
|
||||
```
|
||||
|
||||
在这个命令中,我们使用了 genrsa 子命令,并且设置了输出文件的名称,以及私钥的长度为 1024。运行此命令会在当前文件夹中生成一个 key.pem 文件,这个文件就是我们所需要的私钥文件。
|
||||
|
||||
第二步:生成证书请求
|
||||
|
||||
有了私钥之后,我们就可以生成证书请求了。在使用 openssl 生成证书请求时,可以按照以下命令行来执行:
|
||||
|
||||
```
|
||||
|
||||
openssl req -new -key key.pem -out csr.pem
|
||||
|
||||
```
|
||||
|
||||
在这个命令中,我们使用 req 子命令,并且按照要求设置了私钥和输出文件名。在生成证书请求时,需要输入一些信息,比如你的城市,国家等信息,请根据需求填写相应的信息。
|
||||
|
||||
第三步:签名证书请求
|
||||
|
||||
生成证书请求后,我们需要将证书请求发送给证书颁发机构进行签名。为了在服务器上轻松地创建自签名的 SSL 证书,我们可以使用类似如下的命令或使用 CA 来签署证书请求:
|
||||
|
||||
```
|
||||
|
||||
openssl x509 -req -in csr.pem -out cert.pem -signkey key.pem -days 3650
|
||||
|
||||
```
|
||||
|
||||
在这个命令中,我们使用了 x509 命令,并且指定了证书请求文件名和输出文件名。我们还使用了 -signkey 选项来指定要使用的私钥文件,以便签署证书。再需要指定 -days 选项均是附带了,控制证书的有效期。
|
||||
|
||||
这些选项组合将使用我们之前生成的私钥来签署证书请求,并将其输出到我们指定的文件 cert.pem 中。
|
||||
|
||||
第四步:配置服务器
|
||||
|
||||
在拥有 SSL 证书之后,我们需要将其配置到服务器当中。不同的 Web 服务器和操作系统可能需要不同的配置方式。在这里以 Nginx 服务器作为例子,以简单介绍如何启用 HTTPS。
|
||||
|
||||
首先,请将服务器的私钥和证书文件(key.pem 和 cert.pem)上传到服务器上。
|
||||
|
||||
然后,请在 Nginx 的配置文件中添加以下内容:
|
||||
|
||||
```
|
||||
|
||||
server {
|
||||
|
||||
listen 443;
|
||||
|
||||
server_name your-domain.com;
|
||||
|
||||
ssl on;
|
||||
|
||||
ssl_certificate /path/to/cert.pem;
|
||||
|
||||
ssl_certificate_key /path/to/key.pem;
|
||||
|
||||
# other server configurations…
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
其中,在 ssl_certificate 中指定证书文件的路径(cert.pem),在 ssl_certificate_key 中指定私钥文件的路径(key.pem)。之后重启 Nginx 服务器即可启用 HTTPS。
|
||||
|
||||
在实际项目中,使用 openssl 工具来生成 SSL 证书是常见的一个方法。通过以上的介绍,大家可以了解到 openssl 证书的生成步骤,并能够轻松地将证书配置到自己的 Web 服务器上,确保网站的数据传输安全,提升用户的信任度。
|
||||
@@ -2,7 +2,7 @@ package cn.qaiu.vx.core.util;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ParamUtilTest {
|
||||
|
||||
@@ -11,5 +11,10 @@ public class ParamUtilTest {
|
||||
System.out.println(ParamUtil.paramsToMap(""));
|
||||
System.out.println(ParamUtil.paramsToMap("a=asd&d=23"));
|
||||
System.out.println(ParamUtil.paramsToMap("asdasd&dd"));
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Pattern pattern = Pattern.compile("^(/v2/|/json/).*");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user