Compare commits

..

16 Commits

Author SHA1 Message Date
qaiu
088fee9a4d 1. add:123云盘的新域名
2. update: 统计API支持ce盘
3. 缓存时长
2024-10-01 17:38:57 +08:00
QAIU
d8666acfe8 国庆快乐 ^ ^ #59 2024-09-30 17:42:38 +08:00
QAIU
209e9c2866 国庆快乐 ^ ^ #59 2024-09-30 17:38:36 +08:00
qaiu
6c3195dea4 更新 README.md 2024-09-29 22:11:04 +08:00
qaiu
7d774a7433 更新 README.md 2024-09-29 22:10:23 +08:00
qaiu
f1ec4433cf 更新 README.md 2024-09-29 22:09:58 +08:00
QAIU
1f825db261 update 支持Cloudreve任意https的80端口的域名, 修复因json异常解析导致的解析时间超时的问题 2024-09-25 20:01:10 +08:00
QAIU
1019f24f1d update web-front README.md 2024-09-24 18:05:30 +08:00
QAIU
f5c5b99579 1. 修改文叔叔链接匹配规则 2024-09-24 17:55:18 +08:00
QAIU
e002d19f1b 1. 前端页面优化, 增强统计功能, 支持生成二维码
2. 添加统计接口
2024-09-24 17:08:29 +08:00
qaiu
0d5c9651f0 Update README.md 2024-09-24 10:07:25 +08:00
qaiu
53fc13b95c Merge pull request #56 from qaiu/dependabot/npm_and_yarn/web-front/micromatch-4.0.8
Bump micromatch from 4.0.5 to 4.0.8 in /web-front
2024-09-24 00:09:00 +08:00
QAIU
694c3b0ddc 修复移动云空间无法解析的前端问题, 更新前端依赖 2024-09-23 18:33:09 +08:00
dependabot[bot]
9b3d4577cc Bump micromatch from 4.0.5 to 4.0.8 in /web-front
Bumps [micromatch](https://github.com/micromatch/micromatch) from 4.0.5 to 4.0.8.
- [Release notes](https://github.com/micromatch/micromatch/releases)
- [Changelog](https://github.com/micromatch/micromatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/micromatch/compare/4.0.5...4.0.8)

---
updated-dependencies:
- dependency-name: micromatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-23 08:46:39 +00:00
QAIU
77783915dd 修复移动云空间无法解析的前端问题, 更新前端依赖 2024-09-23 16:45:30 +08:00
qaiu
b67ac21a79 Update README.md add 宝塔安装教程 2024-09-22 17:27:54 +08:00
39 changed files with 6243 additions and 5430 deletions

View File

@@ -7,10 +7,11 @@ main分支依赖JDK17, 提供了JDK11分支[main-jdk11](https://github.com/qaiu/
[![Java CI with Maven](https://github.com/qaiu/netdisk-fast-download/actions/workflows/maven.yml/badge.svg)](https://github.com/qaiu/netdisk-fast-download/actions/workflows/maven.yml)
[![jdk](https://img.shields.io/badge/jdk-%3E%3D17-blue)](https://www.oracle.com/cn/java/technologies/downloads/)
[![vert.x](https://img.shields.io/badge/vert.x-4.5.6-blue)](https://vertx-china.github.io/)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/qaiu/netdisk-fast-download)](https://github.com/qaiu/netdisk-fast-download/releases/tag/0.1.6-releases)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/qaiu/netdisk-fast-download)](https://github.com/qaiu/netdisk-fast-download/releases/latest)
## 项目介绍
网盘直链解析工具能把网盘分享下载链接转化为直链,已支持蓝奏云/蓝奏云优享/奶牛快传/移动云云空间/小飞机盘/亿方云/123云盘/Cloudreve等支持加密分享。
网盘直链解析工具能把网盘分享下载链接转化为直链,已支持蓝奏云/蓝奏云优享/奶牛快传/移动云云空间/小飞机盘/亿方云/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 ~

View File

@@ -22,3 +22,13 @@ Cloudreve自建网盘 (ce) {origin}/s/{shareKey}
https://f.ws59.cn/f/e3peohu6192
开源版 TODO
1. 缓存优化, 配置自动重载
专属版 功能设计
1. 支持绑定域名, 后台管理-账号管理, token管理, 账号解析次数限制
2. 流量统计, 文件分享信息, 目录解析, 文件云下载
3. IP代理池

View File

@@ -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 + '\'' +

View File

@@ -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格式异常");
}
}
}

View File

@@ -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);

View File

@@ -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));
}
}

View File

@@ -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"));

View File

@@ -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");

View File

@@ -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(""));

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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");

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View 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);
}
}

View 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());
}
}

View 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());
});
}
}
}

View File

@@ -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>

View File

@@ -1,7 +1,10 @@
# nfd-web
当前页面修改自开源项目 https://github.com/HurryBy/CloudDiskAnalysis
解析服务的前端页面, 提供API测试, 统计查询, 二维码生成等
![img_2.png](img/img_2.png)
![img.png](img/img.png)
![img_1.png](img/img_1.png)
![11115](https://bd2.qaiu.cn/blog/11115.png)
## Project setup
```
npm install

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
web-front/img/img_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

@@ -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",

View File

@@ -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.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@@ -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;

View File

@@ -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 {

File diff suppressed because it is too large Load Diff

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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 = "";

View File

@@ -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();
}
}

View File

@@ -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;
}

View File

@@ -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");
}

View File

@@ -2,11 +2,14 @@
server:
port: 6400
contextPath: /
# 使用静态页面
enableStaticHtmlService: false
# 使用数据库
enableDatabase: true
# 使用静态页面
enableStaticHtmlService: false
staticResourcePath: webroot/
# 服务域名或者IP
domainName: https://lz.qaiu.top
# 反向代理服务器配置路径(不用加后缀)
proxyConf: server-proxy
@@ -50,8 +53,8 @@ cache:
cow:
ec:
fc:
fj:
iz:
fj: 30
iz: 20
le: 2879
lz:
qq: 999999

View 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

View File

@@ -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,6 +166,11 @@ 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