mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2025-12-16 20:33:03 +00:00
Compare commits
58 Commits
0.1.6-rele
...
0.1.7-rele
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
068efd0503 | ||
|
|
d6de9851df | ||
|
|
a9a048a9ce | ||
|
|
481e7b1240 | ||
|
|
e406e03dc2 | ||
|
|
acbf56adbc | ||
|
|
1cf82b8df9 | ||
|
|
a8405830f2 | ||
|
|
2673f23e64 | ||
|
|
cbaf6e9ac0 | ||
|
|
edb2d65638 | ||
|
|
f8f64fdcb1 | ||
|
|
ae86b85e51 | ||
|
|
c35bc22d02 | ||
|
|
a682d2d876 | ||
|
|
72f363d0e6 | ||
|
|
4b84ecd5fc | ||
|
|
632945d39a | ||
|
|
40bbd3f135 | ||
|
|
d822090c76 | ||
|
|
bd2ab30e7a | ||
|
|
f306170994 | ||
|
|
c8e12de768 | ||
|
|
d602c8a020 | ||
|
|
efe39eef8d | ||
|
|
d828c7ac8b | ||
|
|
37babc9a89 | ||
|
|
8be497a290 | ||
|
|
9ff1ea2ff2 | ||
|
|
fc64363b47 | ||
|
|
36ab2985b1 | ||
|
|
8ba95932ba | ||
|
|
b8aaa59437 | ||
|
|
1d6953d7c7 | ||
|
|
98c336ab84 | ||
|
|
d5e2b9cb3e | ||
|
|
7c4a243429 | ||
|
|
64e312f108 | ||
|
|
265d11e74c | ||
|
|
fcc0f71c23 | ||
|
|
4fd4bfb048 | ||
|
|
da07cfaaff | ||
|
|
7e31adcad9 | ||
|
|
378ae84816 | ||
|
|
a32abe8bfa | ||
|
|
f7ecf3e66c | ||
|
|
e9e503c685 | ||
|
|
85c697ea92 | ||
|
|
2018b20be5 | ||
|
|
e1c61fb51a | ||
|
|
cdeb63e225 | ||
|
|
7b6a79f83a | ||
|
|
dfd7e7a934 | ||
|
|
8deb932685 | ||
|
|
da063461be | ||
|
|
3234f643d5 | ||
|
|
332cc587a2 | ||
|
|
b30d01e154 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -38,3 +38,4 @@ gradlew
|
|||||||
gradlew.bat
|
gradlew.bat
|
||||||
unused.txt
|
unused.txt
|
||||||
/web-service/src/main/generated/
|
/web-service/src/main/generated/
|
||||||
|
/db
|
||||||
|
|||||||
175
README.md
175
README.md
@@ -1,38 +1,38 @@
|
|||||||
# netdisk-fast-download
|
|
||||||
云盘解析服务 (nfd云解析)
|
云盘解析服务 (nfd云解析)
|
||||||
预览地址 https://lz.qaiu.top
|
预览地址 https://lz.qaiu.top
|
||||||
|
**注意: 请不要过度依赖lz.qaiu.top预览地址服务,建议本地搭建或者云服务器自行搭建。
|
||||||
|
解析次数过多IP会被部分网盘厂商限制,不推荐做公共解析。**
|
||||||
|
|
||||||
[](https://github.com/qaiu/netdisk-fast-download/actions/workflows/maven.yml)
|
[](https://github.com/qaiu/netdisk-fast-download/actions/workflows/maven.yml)
|
||||||
[](https://www.oracle.com/cn/java/technologies/downloads/)
|
[](https://www.oracle.com/cn/java/technologies/downloads/)
|
||||||
[](https://vertx-china.github.io/)
|
[](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/tag/0.1.6-releases)
|
||||||
|
|
||||||
## 项目介绍
|
## 项目介绍
|
||||||
网盘直链解析工具能把网盘分享下载链接转化为直链,已支持蓝奏云/奶牛快传/移动云云空间/小飞机盘/亿方云/123云盘等,支持私密分享。
|
网盘直链解析工具能把网盘分享下载链接转化为直链,已支持蓝奏云/蓝奏云优享/奶牛快传/移动云云空间/小飞机盘/亿方云/123云盘/Cloudreve等,支持加密分享。
|
||||||
|
|
||||||
## 应用场景:
|
|
||||||
1. 游戏:使用本站工具可自动生成高速直流下载器,用于游戏客户端自动化高速下载安装、更新等。
|
*重要声明:本项目仅供学习参考;请不要将此项目用于任何商业用途,否则可能带来严重的后果。*
|
||||||
2. 下载:可根据网盘分享的地址解析为直链,方便放到自己网站上供用户下载,节约服务器带宽和磁盘。
|
|
||||||
3. 音视频:可解析为音视频直链,可直接在网页上播放,高清,高速,节约服务器带宽和磁盘。
|
|
||||||
|
|
||||||
## 网盘支持情况:
|
## 网盘支持情况:
|
||||||
> 20230722 UC网盘解析失效,需要登录
|
> 20230905 奶牛云直链做了防盗链,需加入请求头:Referer: https://cowtransfer.com/
|
||||||
|
> 20230824 123云盘解析大文件(>100MB)失效,需要登录
|
||||||
|
> 20230722 UC网盘解析失效,需要登录
|
||||||
|
|
||||||
`网盘名称(网盘标识):`
|
`网盘名称(网盘标识):`
|
||||||
|
|
||||||
- [蓝奏云 (lz)](https://pc.woozooo.com/)
|
- [蓝奏云 (lz)](https://pc.woozooo.com/)
|
||||||
- [ ] 登录, 上传, 下载, 分享
|
- [ ] 登录, 上传, 下载, 分享
|
||||||
- [X] 直链解析
|
- [X] 直链解析
|
||||||
|
- [蓝奏云优享 (iz)](https://www.ilanzou.com/)
|
||||||
|
- [ ] 登录, 上传, 下载, 分享
|
||||||
|
- [X] 直链解析
|
||||||
- [奶牛快传 (cow)](https://cowtransfer.com/)
|
- [奶牛快传 (cow)](https://cowtransfer.com/)
|
||||||
- [ ] 登录, 上传, 下载, 分享
|
- [ ] 登录, 上传, 下载, 分享
|
||||||
- [X] 直链解析
|
- [X] 直链解析
|
||||||
- [移动云空间 (ec)](https://www.ecpan.cn/web)
|
- [移动云空间 (ec)](https://www.ecpan.cn/web)
|
||||||
- [ ] 登录, 上传, 下载, 分享
|
- [ ] 登录, 上传, 下载, 分享
|
||||||
- [X] 直链解析
|
- [X] 直链解析
|
||||||
- [UC网盘 (uc)似乎已经失效,需要登录](https://fast.uc.cn/)
|
|
||||||
- [ ] 登录, 上传, 下载, 分享
|
|
||||||
- [X] 直链解析
|
|
||||||
- [小飞机网盘 (fj)](https://www.feijipan.com/)
|
- [小飞机网盘 (fj)](https://www.feijipan.com/)
|
||||||
- [ ] 登录, 上传, 下载, 分享
|
- [ ] 登录, 上传, 下载, 分享
|
||||||
- [X] 直链解析
|
- [X] 直链解析
|
||||||
@@ -42,39 +42,59 @@
|
|||||||
- [123云盘 (ye)](https://www.123pan.com/)
|
- [123云盘 (ye)](https://www.123pan.com/)
|
||||||
- [ ] 登录, 上传, 下载, 分享
|
- [ ] 登录, 上传, 下载, 分享
|
||||||
- [X] 直链解析
|
- [X] 直链解析
|
||||||
- [文叔叔 (ws) 开发中](https://www.wenshushu.cn/)
|
- [文叔叔 (ws)](https://www.wenshushu.cn/)
|
||||||
- [夸克网盘 (qk) 开发中](https://pan.quark.cn/)
|
- [ ] 登录, 上传, 下载, 分享
|
||||||
|
- [X] 直链解析
|
||||||
|
- [Cloudreve自建网盘 (ce)](https://github.com/cloudreve/Cloudreve)
|
||||||
|
- [ ] 登录, 上传, 下载, 分享
|
||||||
|
- [X] 直链解析
|
||||||
|
- [QQ邮箱 (qq) 暂不可用-存在cookie问题](https://wx.mail.qq.com/)
|
||||||
|
- [ ] 登录, 上传, 下载, 分享
|
||||||
|
- [X] 直链解析(用户无法直接使用直链)
|
||||||
|
- [夸克网盘 (qk) 寄了](https://pan.quark.cn/)
|
||||||
|
- [UC网盘 (uc) 寄了](https://fast.uc.cn/)
|
||||||
|
|
||||||
**TODO:**
|
**TODO:**
|
||||||
- 登录接口, 文件上传/下载/分享后端接口
|
- 登录接口, 文件上传/下载/分享后端接口
|
||||||
- 短地址服务
|
- 短地址服务
|
||||||
- 前端界面(建设中...)
|
- 前端界面(建设中...)
|
||||||
|
|
||||||
**技术栈:**
|
### API接口说明
|
||||||
Jdk17+Vert.x4.4.1
|
your_host指的是您的域名或者IP,实际使用时替换为实际域名或者IP。
|
||||||
Core模块集成Vert.x实现类似spring的注解式路由API
|
解析方式分为两种类型直接跳转下载链接和获取下载链接(JSON),每一种都提供了两种接口形式parser和网盘标志/分享key拼接的短地址(标志短链),所有规则参考示例。
|
||||||
|
- 通用接口: `/parser?url=分享链接`,加密分享需要加上参数pwd=密码;
|
||||||
API接口
|
- 标志短链: `/网盘标识/分享key` 在分享Key后面加上@密码;
|
||||||
|
- 直链JSON: `通用接口`和`标志短链`前加上`/json` 加密分享的密码规则同上;
|
||||||
|
- 网盘标识参考上面网盘支持情况
|
||||||
|
- 括号内是可选内容: 表示当带有分享密码时需要加上密码参数
|
||||||
|
- 移动云空间,小飞机网盘的加密分享的密码可以忽略
|
||||||
|
|
||||||
|
规则示例:
|
||||||
```
|
```
|
||||||
网盘标识参考上面网盘支持情况, 括号内是可选内容: 表示当带有分享密码时需要加上密码参数
|
|
||||||
parser接口可以直接解析分享链接: 加密分享需要加上参数pwd=密码;
|
|
||||||
其他接口在分享Key后面加上@密码;
|
|
||||||
|
|
||||||
1. 解析并自动302跳转 :
|
1. 解析并自动302跳转 :
|
||||||
http(s)://your_host/parser?url=分享链接(&pwd=xxx)
|
http://your_host/parser?url=分享链接(&pwd=xxx)
|
||||||
http(s)://your_host/网盘标识/分享key(@分享密码)
|
http://your_host/网盘标识/分享key(@分享密码)
|
||||||
2. 获取解析后的直链--JSON格式
|
2. 获取解析后的直链--JSON格式
|
||||||
http(s)://your_host/json/parser?url=分享链接(&pwd=xxx)
|
http://your_host/json/parser?url=分享链接(&pwd=xxx)
|
||||||
http(s)://your_host/json/网盘标识/分享key(@分享密码)
|
http://your_host/json/网盘标识/分享key(@分享密码)
|
||||||
3. 特别注意的地方:
|
3. 需要特殊处理的网盘分享:
|
||||||
- 有些网盘的加密分享的密码可以忽略: 如移动云空间,小飞机网盘
|
1. 移动云空间(ec)使用parser?url= 解析时因为分享链接比较特殊(链接带有参数且含有#符号)所以要么对#进行转义%23要么直接去掉# 或者URL直接是主机名+'/'跟一个data参数
|
||||||
- 移动云空间(ec)使用parser?url= 解析时因为分享链接比较特殊(链接带有参数且含有#符号)所以要么对#进行转义%23要么直接去掉# 或者URL直接是主机名+'/'跟一个data参数
|
|
||||||
比如 http://your_host/parser?url=https://www.ecpan.cn/web//yunpanProxy?path=%2F%23%2Fdrive%2Foutside&data=81027a5c99af5b11ca004966c945cce6W9Bf2&isShare=1
|
比如 http://your_host/parser?url=https://www.ecpan.cn/web//yunpanProxy?path=%2F%23%2Fdrive%2Foutside&data=81027a5c99af5b11ca004966c945cce6W9Bf2&isShare=1
|
||||||
http://your_host/parser?url=https://www.ecpan.cn/web/%23/yunpanProxy?path=%2F%23%2Fdrive%2Foutside&data=81027a5c99af5b11ca004966c945cce6W9Bf2&isShare=1
|
http://your_host/parser?url=https://www.ecpan.cn/web/%23/yunpanProxy?path=%2F%23%2Fdrive%2Foutside&data=81027a5c99af5b11ca004966c945cce6W9Bf2&isShare=1
|
||||||
http://your_host/parser?url=https://www.ecpan.cn/&data=81027a5c99af5b11ca004966c945cce6W9Bf2&isShare=1
|
http://your_host/parser?url=https://www.ecpan.cn/&data=81027a5c99af5b11ca004966c945cce6W9Bf2&isShare=1
|
||||||
|
|
||||||
|
2. Cloudreve自建网盘解析规则:
|
||||||
|
1. 标志短链: 根据网盘使用https和http选择 http://your_host/ce/https_网盘域名_s_wDz5TK 或 http://your_host/ce/http_网盘域名_s_wDz5TK
|
||||||
|
网盘域名指的是Cloudreve搭建网盘的主域名比如pan.huang1111.cn,如果存在子路径需要将/替换为_,是否存在子路径看分享链接格式是否是://网盘域名/子路径/s/xxx,一般不存在子路径:网盘域名/s/xxx,
|
||||||
|
比如: http://127.0.0.1:6400/ce/https_pan.huang1111.cn_s_wDz5TK
|
||||||
|
2. parser接口 -> http://your_host/parser?url=分享链接(&pwd=xxx)
|
||||||
|
比如: http://127.0.0.1:6400/parser?url=https://pan.huang1111.cn/s/wDz5TK
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
json返回数据格式示例:
|
json返回数据格式示例:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"code": 200,
|
"code": 200,
|
||||||
@@ -125,70 +145,95 @@ GET http://127.0.0.1:6400/json/fc/e5079007dc31226096628870c7@QAIU
|
|||||||
# 网盘对比
|
# 网盘对比
|
||||||
|
|
||||||
|
|
||||||
| 网盘名称 | 可直接下载分享 | 加密分享 | 初始网盘空间 | 单文件大小限制 | 登录接口 |
|
| 网盘名称 | 可直接下载分享 | 加密分享 | 初始网盘空间 | 单文件大小限制 | 登录接口 |
|
||||||
|------------|------------------------|----------|-----------|---------|------|
|
|------------|------------------------|----------|-----------|-----------------|------|
|
||||||
| 蓝奏云 | √ | √ | 不限空间 | 100M | TODO |
|
| 蓝奏云 | √ | √ | 不限空间 | 100M | TODO |
|
||||||
| 奶牛快传 | √ | X | 10G | 不限大小 | TODO |
|
| 奶牛快传 | √ | X | 10G | 不限大小 | TODO |
|
||||||
| 移动云空间 | √ | √(密码可忽略) | 5G(个人) | 不限大小 | TODO |
|
| 移动云空间 | √ | √(密码可忽略) | 5G(个人) | 不限大小 | TODO |
|
||||||
| UC网盘 | 需要登录 | √ | 10G | 不限大小 | TODO |
|
| UC网盘 | 需要登录 | √ | 10G | 不限大小 | TODO |
|
||||||
| 小飞机网盘 | √ | √(密码可忽略) | 10G | 不限大小 | TODO |
|
| 小飞机网盘 | √ | √(密码可忽略) | 10G | 不限大小 | TODO |
|
||||||
| 360亿方云 | √(试用账号有时间限制企业版需要599续费) | √(密码可忽略) | 100G(须实名) | 不限大小 | TODO |
|
| 360亿方云 | √(试用账号有时间限制企业版需要599续费) | √(密码可忽略) | 100G(须实名) | 不限大小 | TODO |
|
||||||
| 123云盘 | √ | √ | 2T | 100G | TODO |
|
| 123云盘 | √ | √ | 2T | 100G(>100M需要登录) | TODO |
|
||||||
| 文叔叔(TODO) | √(注意有时间限制) | √ | 10G | 5GB | TODO |
|
| 文叔叔(TODO) | √(注意有时间限制) | √ | 10G | 5GB | TODO |
|
||||||
| 夸克网盘(TODO) | 需要登录 | √ | 10G | 不限大小 | TODO |
|
| 夸克网盘(TODO) | 需要登录 | √ | 10G | 不限大小 | TODO |
|
||||||
|
|
||||||
# 打包部署
|
# 打包部署
|
||||||
|
|
||||||
## JDK下载(lz.qaiu.top提供直链云解析服务)
|
## JDK下载(lz.qaiu.top提供直链云解析服务)
|
||||||
- [阿里jdk17(Dragonwell17-windows-x86)](https://lz.qaiu.top/ye/iaKtVv-hbECd)
|
- [阿里jdk17(Dragonwell17-windows-x86)](https://lz.qaiu.top/ec/e957acef36ce89e1053979672a90d219n)
|
||||||
- [阿里jdk17(Dragonwell17-linux-x86)](https://lz.qaiu.top/ye/iaKtVv-AbECd)
|
- [阿里jdk17(Dragonwell17-linux-x86)](https://lz.qaiu.top/ec/6ebc9f2e0bbd53b4c4d5b11013f40a80NHvcYU)
|
||||||
- [阿里jdk17(Dragonwell17-linux-aarch64)](https://lz.qaiu.top/ye/iaKtVv-HbECd)
|
- [阿里jdk17(Dragonwell17-linux-aarch64)](https://lz.qaiu.top/ec/d14c2d06296f61b52a876b525265e0f8tzxTc5)
|
||||||
- [123云盘解析有效性测试用-阿里jdk17(Dragonwell17-linux-aarch64)](https://lz.qaiu.top/json/ye/iaKtVv-HbECd)
|
- [解析有效性测试-移动云空间-阿里jdk17-linux-x86](https://lz.qaiu.top/json/ec/6ebc9f2e0bbd53b4c4d5b11013f40a80NHvcYU)
|
||||||
|
|
||||||
## 开发和打包
|
## 开发和打包
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# 环境要求: Jdk17 + maven;
|
# 环境要求: Jdk17 + maven;
|
||||||
mvn clean
|
mvn clean
|
||||||
mvn package
|
mvn package
|
||||||
|
|
||||||
```
|
```
|
||||||
打包好的文件位于 web-service/target/netdisk-fast-download-x.x.x-bin.zip
|
打包好的文件位于 web-service/target/netdisk-fast-download-bin.zip
|
||||||
## Linux服务部署
|
## Linux服务部署
|
||||||
> 注意: netdisk-fast-download.service中的ExecStart的路径改为实际路径
|
> 注意: netdisk-fast-download.service中的ExecStart的路径改为实际路径
|
||||||
```shell
|
```shell
|
||||||
cd ~
|
cd ~
|
||||||
wget -O netdisk-fast-download-0.1.6-bin.zip https://github.com/qaiu/netdisk-fast-download/releases/download/0.1.6-releases/netdisk-fast-download-0.1.6-bin.zip
|
wget -O netdisk-fast-download.zip https://github.com/qaiu/netdisk-fast-download/releases/download/0.1.7/netdisk-fast-download.zip
|
||||||
unzip netdisk-fast-download-*-bin.zip
|
unzip netdisk-fast-download-bin.zip
|
||||||
cd netdisk-fast-download-*-bin
|
cd netdisk-fast-download
|
||||||
bash service-install.sh
|
bash service-install.sh
|
||||||
```
|
```
|
||||||
服务相关命令:
|
服务相关命令:
|
||||||
1、查看服务状态
|
|
||||||
systemctl status netdisk-fast-download.service
|
|
||||||
|
|
||||||
2、控制服务
|
查看服务状态
|
||||||
|
`systemctl status netdisk-fast-download.service`
|
||||||
|
|
||||||
启动服务
|
启动服务
|
||||||
systemctl start netdisk-fast-download.service
|
`systemctl start netdisk-fast-download.service`
|
||||||
|
|
||||||
重启服务
|
重启服务
|
||||||
systemctl restart netdisk-fast-download.service
|
`systemctl restart netdisk-fast-download.service`
|
||||||
|
|
||||||
停止服务
|
停止服务
|
||||||
systemctl stop netdisk-fast-download.service
|
`systemctl stop netdisk-fast-download.service`
|
||||||
|
|
||||||
开机启动服务
|
开机启动服务
|
||||||
systemctl enable netdisk-fast-download.servic
|
`systemctl enable netdisk-fast-download.servic`
|
||||||
|
|
||||||
停止开机启动
|
停止开机启动
|
||||||
systemctl disable netdisk-fast-download.servic
|
`systemctl disable netdisk-fast-download.servic`
|
||||||
|
|
||||||
## Windows服务部署
|
## Windows服务部署
|
||||||
1. 下载并解压releases版本netdisk-fast-download-0.1.6-bin.zip
|
1. 下载并解压releases版本netdisk-fast-download-bin.zip
|
||||||
2. 进入netdisk-fast-download-0.1.6-bin目录
|
2. 进入netdisk-fast-download下的bin目录
|
||||||
3. 使用管理员权限运行nfd-service-install.bat
|
3. 使用管理员权限运行nfd-service-install.bat
|
||||||
如果不想使用服务运行可以直接运行run.bat
|
如果不想使用服务运行可以直接运行run.bat
|
||||||
> 注意: 如果jdk环境变量的java版本不是17请修改nfd-service-template.xml中的java命令的路径改为实际路径
|
> 注意: 如果jdk环境变量的java版本不是17请修改nfd-service-template.xml中的java命令的路径改为实际路径
|
||||||
|
|
||||||
## Docker部署
|
## 0.1.8 开发计划
|
||||||
TODO
|
- Docker部署
|
||||||
|
- 联想乐云解析支持
|
||||||
|
- CLoudreve解析解析
|
||||||
|
- 直链缓存
|
||||||
|
- 日志优化
|
||||||
|
|
||||||
|
|
||||||
|
**技术栈:**
|
||||||
|
Jdk17+Vert.x4.4.1
|
||||||
|
Core模块集成Vert.x实现类似spring的注解式路由API
|
||||||
|
|
||||||
|
|
||||||
|
## Star History
|
||||||
|
|
||||||
|
[](https://star-history.com/#qaiu/netdisk-fast-download&Date)
|
||||||
|
|
||||||
|
|
||||||
|
## 支持该项目
|
||||||
|
本项目长期维护如果觉得有帮助, 可以请作者喝杯咖啡, 感谢支持
|
||||||
|

|
||||||
|
|
||||||
|
[手机端支付宝打赏跳转链接](https://qr.alipay.com/fkx01882dnoxxtjenhlxt53)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Wants=network-online.target
|
|||||||
Type=simple
|
Type=simple
|
||||||
# User=USER
|
# User=USER
|
||||||
# 需要JDK17及以上版本 注意修改为自己的路径
|
# 需要JDK17及以上版本 注意修改为自己的路径
|
||||||
ExecStart=/root/java/jdk-17.0.2/bin/java -server -Xmx128m -jar /root/java/netdisk-fast-download-0.1.6/netdisk-fast-download-0.1.6.jar
|
ExecStart=/root/java/jdk-17.0.2/bin/java -server -Xmx128m -jar /root/java/netdisk-fast-download/netdisk-fast-download.jar
|
||||||
ExecStop=/bin/kill -s QUIT $MAINPID
|
ExecStop=/bin/kill -s QUIT $MAINPID
|
||||||
Restart=always
|
Restart=always
|
||||||
StandOutput=syslog
|
StandOutput=syslog
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ pushd %~dp0
|
|||||||
set MY_DIR=%~dp0
|
set MY_DIR=%~dp0
|
||||||
set MY_DIR=%MY_DIR:~0,-1%
|
set MY_DIR=%MY_DIR:~0,-1%
|
||||||
|
|
||||||
for /f "delims=X" %%i in ('dir /b %MY_DIR%\netdisk-fast-download-*.jar') do (
|
for /f "delims=X" %%i in ('dir /b %MY_DIR%\netdisk-fast-download.jar') do (
|
||||||
set LAUNCH_JAR=%MY_DIR%\%%i
|
set LAUNCH_JAR=%MY_DIR%\%%i
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
@echo off && @chcp 65001 > nul
|
@echo off && @chcp 65001 > nul
|
||||||
pushd %~dp0
|
pushd %~dp0
|
||||||
set LIB_DIR=%~dp0
|
set LIB_DIR=%~dp0
|
||||||
for /f "delims=X" %%i in ('dir /b %LIB_DIR%\netdisk-fast-download-*.jar') do (
|
for /f "delims=X" %%i in ('dir /b %LIB_DIR%\netdisk-fast-download.jar') do (
|
||||||
set LAUNCH_JAR=%LIB_DIR%%%i
|
set LAUNCH_JAR=%LIB_DIR%%%i
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set "JAVA_HOME=D:\App\dragonwell-17.0.3.0.3+7-GA"
|
||||||
"%JAVA_HOME%\bin\java.exe" -Xmx512M -Dfile.encoding=utf8 -jar %LAUNCH_JAR% %*
|
"%JAVA_HOME%\bin\java.exe" -Xmx512M -Dfile.encoding=utf8 -jar %LAUNCH_JAR% %*
|
||||||
|
|
||||||
pause
|
pause
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# set -x
|
# set -x
|
||||||
LAUNCH_JAR="netdisk-fast-download-0.1.6.jar"
|
LAUNCH_JAR="netdisk-fast-download.jar"
|
||||||
nohup java -Xmx512M -jar "$LAUNCH_JAR" "$@" >startup.log 2>&1 &
|
nohup java -Xmx512M -jar "$LAUNCH_JAR" "$@" >startup.log 2>&1 &
|
||||||
tail -f startup.log
|
tail -f startup.log
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>netdisk-fast-download</artifactId>
|
<artifactId>netdisk-fast-download</artifactId>
|
||||||
<groupId>cn.qaiu</groupId>
|
<groupId>cn.qaiu</groupId>
|
||||||
<version>0.1.6</version>
|
<version>0.1.7</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<slf4j.version>2.0.5</slf4j.version>
|
<slf4j.version>2.0.5</slf4j.version>
|
||||||
<commons-lang3.version>3.12.0</commons-lang3.version>
|
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||||
<vertx.version>4.4.1</vertx.version>
|
<vertx.version>4.5.6</vertx.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package cn.qaiu;
|
package cn.qaiu;
|
||||||
|
|
||||||
public class StartH2DatabaseServer {
|
public class StartH2DatabaseServer {
|
||||||
public static void main(String[] args) {
|
|
||||||
System.out.println("Hello world!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public class CreateTable {
|
|||||||
javaProperty2SqlColumnMap.put(Boolean.class, "BOOLEAN");
|
javaProperty2SqlColumnMap.put(Boolean.class, "BOOLEAN");
|
||||||
javaProperty2SqlColumnMap.put(String.class, "VARCHAR");
|
javaProperty2SqlColumnMap.put(String.class, "VARCHAR");
|
||||||
javaProperty2SqlColumnMap.put(java.util.Date.class, "TIMESTAMP");
|
javaProperty2SqlColumnMap.put(java.util.Date.class, "TIMESTAMP");
|
||||||
|
javaProperty2SqlColumnMap.put(java.time.LocalDateTime.class, "TIMESTAMP");
|
||||||
javaProperty2SqlColumnMap.put(java.sql.Timestamp.class, "TIMESTAMP");
|
javaProperty2SqlColumnMap.put(java.sql.Timestamp.class, "TIMESTAMP");
|
||||||
javaProperty2SqlColumnMap.put(java.sql.Date.class, "DATE");
|
javaProperty2SqlColumnMap.put(java.sql.Date.class, "DATE");
|
||||||
javaProperty2SqlColumnMap.put(java.sql.Time.class, "TIME");
|
javaProperty2SqlColumnMap.put(java.sql.Time.class, "TIME");
|
||||||
|
|||||||
16
core/pom.xml
16
core/pom.xml
@@ -5,22 +5,14 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>netdisk-fast-download</artifactId>
|
<artifactId>netdisk-fast-download</artifactId>
|
||||||
<groupId>cn.qaiu</groupId>
|
<groupId>cn.qaiu</groupId>
|
||||||
<version>0.1.6</version>
|
<version>0.1.7</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<version>1.0.8</version>
|
<version>1.0.8</version>
|
||||||
<artifactId>core</artifactId>
|
<artifactId>core</artifactId>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>17</java.version>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<vertx.version>4.4.1</vertx.version>
|
|
||||||
<org.reflections.version>0.10.2</org.reflections.version>
|
|
||||||
<lombok.version>1.18.12</lombok.version>
|
|
||||||
<slf4j.version>2.0.5</slf4j.version>
|
|
||||||
<commons-lang3.version>3.12.0</commons-lang3.version>
|
|
||||||
<jackson.version>2.14.2</jackson.version>
|
|
||||||
<logback.version>1.4.6</logback.version>
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
@@ -91,6 +83,12 @@
|
|||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
<version>${jackson.version}</version>
|
<version>${jackson.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||||
|
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||||
|
<version>${jackson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,11 @@ public final class Deploy {
|
|||||||
return INSTANCE;
|
return INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param args 启动参数
|
||||||
|
* @param handle 启动完成后回调处理函数
|
||||||
|
*/
|
||||||
public void start(String[] args, Handler<JsonObject> handle) {
|
public void start(String[] args, Handler<JsonObject> handle) {
|
||||||
this.mainThread = Thread.currentThread();
|
this.mainThread = Thread.currentThread();
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
package cn.qaiu.vx.core.base;
|
package cn.qaiu.vx.core.base;
|
||||||
|
|
||||||
import cn.qaiu.vx.core.interceptor.AfterInterceptor;
|
import cn.qaiu.vx.core.interceptor.AfterInterceptor;
|
||||||
|
import cn.qaiu.vx.core.model.JsonResult;
|
||||||
|
import cn.qaiu.vx.core.util.CommonUtil;
|
||||||
|
import cn.qaiu.vx.core.util.ReflectionUtil;
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
|
import org.reflections.Reflections;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE;
|
import static cn.qaiu.vx.core.util.ResponseUtil.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 统一响应处理
|
* 统一响应处理
|
||||||
@@ -16,43 +20,43 @@ import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE;
|
|||||||
*/
|
*/
|
||||||
public interface BaseHttpApi {
|
public interface BaseHttpApi {
|
||||||
|
|
||||||
default Set<AfterInterceptor> getAfterInterceptor() {
|
// 需要扫描注册的Router路径
|
||||||
return null;
|
Reflections reflections = ReflectionUtil.getReflections();
|
||||||
}
|
|
||||||
|
|
||||||
default void fireJsonResponse(RoutingContext ctx, JsonObject jsonResult) {
|
default void doFireJsonObjectResponse(RoutingContext ctx, JsonObject jsonObject) {
|
||||||
ctx.response().putHeader(CONTENT_TYPE, "application/json; charset=utf-8")
|
|
||||||
.setStatusCode(200)
|
|
||||||
.end(jsonResult.encode());
|
|
||||||
}
|
|
||||||
|
|
||||||
default <T> void fireJsonResponse(RoutingContext ctx, T jsonResult) {
|
|
||||||
JsonObject jsonObject = JsonObject.mapFrom(jsonResult);
|
|
||||||
if (!ctx.response().ended()) {
|
if (!ctx.response().ended()) {
|
||||||
fireJsonResponse(ctx, jsonObject);
|
fireJsonObjectResponse(ctx, jsonObject);
|
||||||
}
|
}
|
||||||
handleAfterInterceptor(ctx, jsonObject);
|
handleAfterInterceptor(ctx, jsonObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
default void handleAfterInterceptor(RoutingContext ctx, JsonObject jsonObject){
|
|
||||||
|
default <T> void doFireJsonResultResponse(RoutingContext ctx, JsonResult<T> jsonResult) {
|
||||||
|
if (!ctx.response().ended()) {
|
||||||
|
fireJsonResultResponse(ctx, jsonResult);
|
||||||
|
}
|
||||||
|
handleAfterInterceptor(ctx, jsonResult.toJsonObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
default Set<AfterInterceptor> getAfterInterceptor() {
|
||||||
|
|
||||||
|
Set<Class<? extends AfterInterceptor>> afterInterceptorClassSet =
|
||||||
|
reflections.getSubTypesOf(AfterInterceptor.class);
|
||||||
|
if (afterInterceptorClassSet == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return CommonUtil.sortClassSet(afterInterceptorClassSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
default void handleAfterInterceptor(RoutingContext ctx, JsonObject jsonObject) {
|
||||||
Set<AfterInterceptor> afterInterceptor = getAfterInterceptor();
|
Set<AfterInterceptor> afterInterceptor = getAfterInterceptor();
|
||||||
if (afterInterceptor != null) {
|
if (afterInterceptor != null) {
|
||||||
afterInterceptor.forEach(ai -> ai.handle(ctx.request(), jsonObject));
|
afterInterceptor.forEach(ai -> ai.handle(ctx, jsonObject));
|
||||||
}
|
}
|
||||||
if (!ctx.response().ended()) {
|
if (!ctx.response().ended()) {
|
||||||
fireJsonResponse(ctx, "handleAfterInterceptor end.");
|
fireTextResponse(ctx, "handleAfterInterceptor: response not end");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default void fireTextResponse(RoutingContext ctx, String text) {
|
|
||||||
ctx.response().putHeader(CONTENT_TYPE, "text/html; charset=utf-8").end(text);
|
|
||||||
Set<AfterInterceptor> afterInterceptor = getAfterInterceptor();
|
|
||||||
if (afterInterceptor != null) {
|
|
||||||
afterInterceptor.forEach(ai -> ai.handle(ctx.request(), new JsonObject().put("text", text)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
default void sendError(int statusCode, RoutingContext ctx) {
|
|
||||||
ctx.response().setStatusCode(statusCode).end();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package cn.qaiu.vx.core.handlerfactory;
|
package cn.qaiu.vx.core.handlerfactory;
|
||||||
|
|
||||||
import cn.qaiu.vx.core.annotaions.*;
|
import cn.qaiu.vx.core.annotaions.DateFormat;
|
||||||
|
import cn.qaiu.vx.core.annotaions.RouteHandler;
|
||||||
|
import cn.qaiu.vx.core.annotaions.RouteMapping;
|
||||||
|
import cn.qaiu.vx.core.annotaions.SockRouteMapper;
|
||||||
import cn.qaiu.vx.core.base.BaseHttpApi;
|
import cn.qaiu.vx.core.base.BaseHttpApi;
|
||||||
import cn.qaiu.vx.core.interceptor.AfterInterceptor;
|
|
||||||
import cn.qaiu.vx.core.interceptor.BeforeInterceptor;
|
import cn.qaiu.vx.core.interceptor.BeforeInterceptor;
|
||||||
import cn.qaiu.vx.core.model.JsonResult;
|
import cn.qaiu.vx.core.model.JsonResult;
|
||||||
import cn.qaiu.vx.core.util.*;
|
import cn.qaiu.vx.core.util.*;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
import io.vertx.core.Handler;
|
import io.vertx.core.Handler;
|
||||||
import io.vertx.core.MultiMap;
|
import io.vertx.core.MultiMap;
|
||||||
@@ -17,16 +20,12 @@ import io.vertx.core.json.JsonObject;
|
|||||||
import io.vertx.ext.web.Route;
|
import io.vertx.ext.web.Route;
|
||||||
import io.vertx.ext.web.Router;
|
import io.vertx.ext.web.Router;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import io.vertx.ext.web.handler.BodyHandler;
|
import io.vertx.ext.web.handler.*;
|
||||||
import io.vertx.ext.web.handler.CorsHandler;
|
|
||||||
import io.vertx.ext.web.handler.StaticHandler;
|
|
||||||
import io.vertx.ext.web.handler.TimeoutHandler;
|
|
||||||
import io.vertx.ext.web.handler.sockjs.SockJSHandler;
|
import io.vertx.ext.web.handler.sockjs.SockJSHandler;
|
||||||
import io.vertx.ext.web.handler.sockjs.SockJSHandlerOptions;
|
import io.vertx.ext.web.handler.sockjs.SockJSHandlerOptions;
|
||||||
import javassist.CtClass;
|
import javassist.CtClass;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.reflections.Reflections;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -57,14 +56,11 @@ public class RouterHandlerFactory implements BaseHttpApi {
|
|||||||
add(HttpMethod.DELETE);
|
add(HttpMethod.DELETE);
|
||||||
add(HttpMethod.HEAD);
|
add(HttpMethod.HEAD);
|
||||||
}};
|
}};
|
||||||
// 需要扫描注册的Router路径
|
|
||||||
private static volatile Reflections reflections;
|
|
||||||
|
|
||||||
private final String gatewayPrefix;
|
private final String gatewayPrefix;
|
||||||
|
|
||||||
public RouterHandlerFactory(String gatewayPrefix) {
|
public RouterHandlerFactory(String gatewayPrefix) {
|
||||||
Objects.requireNonNull(gatewayPrefix, "The gateway prefix is empty.");
|
Objects.requireNonNull(gatewayPrefix, "The gateway prefix is empty.");
|
||||||
reflections = ReflectionUtil.getReflections();
|
|
||||||
this.gatewayPrefix = gatewayPrefix;
|
this.gatewayPrefix = gatewayPrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +126,7 @@ public class RouterHandlerFactory implements BaseHttpApi {
|
|||||||
LOGGER.error("Manually Register Handler Fail, Error details:" + e.getMessage());
|
LOGGER.error("Manually Register Handler Fail, Error details:" + e.getMessage());
|
||||||
}
|
}
|
||||||
// 错误请求处理
|
// 错误请求处理
|
||||||
mainRouter.errorHandler(405, ctx -> fireJsonResponse(ctx, JsonResult
|
mainRouter.errorHandler(405, ctx -> doFireJsonResultResponse(ctx, JsonResult
|
||||||
.error("Method Not Allowed", 405)));
|
.error("Method Not Allowed", 405)));
|
||||||
mainRouter.errorHandler(404, ctx -> ctx.response().setStatusCode(404).setChunked(true)
|
mainRouter.errorHandler(404, ctx -> ctx.response().setStatusCode(404).setChunked(true)
|
||||||
.end("Internal server error: 404 not found"));
|
.end("Internal server error: 404 not found"));
|
||||||
@@ -165,7 +161,7 @@ public class RouterHandlerFactory implements BaseHttpApi {
|
|||||||
// 普通路由
|
// 普通路由
|
||||||
RouteMapping mapping = method.getAnnotation(RouteMapping.class);
|
RouteMapping mapping = method.getAnnotation(RouteMapping.class);
|
||||||
HttpMethod routeMethod = HttpMethod.valueOf(mapping.method().name());
|
HttpMethod routeMethod = HttpMethod.valueOf(mapping.method().name());
|
||||||
String routeUrl = getRouteUrl(method.getName(), mapping.value());
|
String routeUrl = getRouteUrl(mapping.value());
|
||||||
String url = root.concat(routeUrl);
|
String url = root.concat(routeUrl);
|
||||||
// 匹配方法
|
// 匹配方法
|
||||||
Route route = router.route(routeMethod, url);
|
Route route = router.route(routeMethod, url);
|
||||||
@@ -177,15 +173,16 @@ public class RouterHandlerFactory implements BaseHttpApi {
|
|||||||
|
|
||||||
// 设置默认超时
|
// 设置默认超时
|
||||||
route.handler(TimeoutHandler.create(SharedDataUtil.getCustomConfig().getInteger(ROUTE_TIME_OUT)));
|
route.handler(TimeoutHandler.create(SharedDataUtil.getCustomConfig().getInteger(ROUTE_TIME_OUT)));
|
||||||
|
route.handler(ResponseTimeHandler.create());
|
||||||
route.handler(ctx -> handlerMethod(instance, method, ctx)).failureHandler(ctx -> {
|
route.handler(ctx -> handlerMethod(instance, method, ctx)).failureHandler(ctx -> {
|
||||||
if (ctx.response().ended()) return;
|
if (ctx.response().ended()) return;
|
||||||
ctx.failure().printStackTrace();
|
ctx.failure().printStackTrace();
|
||||||
fireJsonResponse(ctx, JsonResult.error(ctx.failure().getMessage(), 500));
|
doFireJsonResultResponse(ctx, JsonResult.error(ctx.failure().getMessage(), 500));
|
||||||
});
|
});
|
||||||
} else if (method.isAnnotationPresent(SockRouteMapper.class)) {
|
} else if (method.isAnnotationPresent(SockRouteMapper.class)) {
|
||||||
// websocket 基于sockJs
|
// websocket 基于sockJs
|
||||||
SockRouteMapper mapping = method.getAnnotation(SockRouteMapper.class);
|
SockRouteMapper mapping = method.getAnnotation(SockRouteMapper.class);
|
||||||
String routeUrl = getRouteUrl(method.getName(), mapping.value());
|
String routeUrl = getRouteUrl(mapping.value());
|
||||||
String url = root.concat(routeUrl);
|
String url = root.concat(routeUrl);
|
||||||
LOGGER.info("Register New Websocket Handler -> {}", url);
|
LOGGER.info("Register New Websocket Handler -> {}", url);
|
||||||
SockJSHandlerOptions options = new SockJSHandlerOptions()
|
SockJSHandlerOptions options = new SockJSHandlerOptions()
|
||||||
@@ -212,10 +209,9 @@ public class RouterHandlerFactory implements BaseHttpApi {
|
|||||||
/**
|
/**
|
||||||
* 获取并处理路由URL分隔符
|
* 获取并处理路由URL分隔符
|
||||||
*
|
*
|
||||||
* @param methodName 路由method
|
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
private String getRouteUrl(String methodName, String mapperValue) {
|
private String getRouteUrl(String mapperValue) {
|
||||||
String routeUrl;
|
String routeUrl;
|
||||||
if ("/".equals(mapperValue)) {
|
if ("/".equals(mapperValue)) {
|
||||||
routeUrl = mapperValue;
|
routeUrl = mapperValue;
|
||||||
@@ -231,7 +227,6 @@ public class RouterHandlerFactory implements BaseHttpApi {
|
|||||||
* 配置拦截
|
* 配置拦截
|
||||||
*
|
*
|
||||||
* @return Handler
|
* @return Handler
|
||||||
* @throws Throwable Throwable
|
|
||||||
*/
|
*/
|
||||||
private Set<Handler<RoutingContext>> getInterceptorSet() {
|
private Set<Handler<RoutingContext>> getInterceptorSet() {
|
||||||
// 配置拦截
|
// 配置拦截
|
||||||
@@ -257,7 +252,7 @@ public class RouterHandlerFactory implements BaseHttpApi {
|
|||||||
if (handler.isAnnotationPresent(RouteHandler.class)) {
|
if (handler.isAnnotationPresent(RouteHandler.class)) {
|
||||||
RouteHandler routeHandler = handler.getAnnotation(RouteHandler.class);
|
RouteHandler routeHandler = handler.getAnnotation(RouteHandler.class);
|
||||||
String value = routeHandler.value();
|
String value = routeHandler.value();
|
||||||
root += ("/".equals(value) ? "" : value);
|
root += (value.startsWith("/") ? value.substring(1) : value);
|
||||||
}
|
}
|
||||||
if (!root.endsWith("/")) {
|
if (!root.endsWith("/")) {
|
||||||
root = root + "/";
|
root = root + "/";
|
||||||
@@ -300,37 +295,12 @@ public class RouterHandlerFactory implements BaseHttpApi {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
final MultiMap queryParams = ctx.queryParams();
|
|
||||||
if ("POST".equals(ctx.request().method().name())) {
|
|
||||||
queryParams.addAll(ctx.request().params());
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonArray entityPackagesReg = SharedDataUtil.getJsonArrayForCustomConfig("entityPackagesReg");
|
JsonArray entityPackagesReg = SharedDataUtil.getJsonArrayForCustomConfig("entityPackagesReg");
|
||||||
// 绑定get或post请求头的请求参数
|
|
||||||
methodParametersTemp.forEach((k, v) -> {
|
final MultiMap queryParams = ctx.queryParams();
|
||||||
if (ReflectionUtil.isBasicType(v.getRight())) {
|
|
||||||
String fmt = getFmt(v.getLeft(), v.getRight());
|
|
||||||
String value = queryParams.get(k);
|
|
||||||
parameterValueList.put(k, ReflectionUtil.conversion(v.getRight(), value, fmt));
|
|
||||||
} else if (RoutingContext.class.getName().equals(v.getRight().getName())) {
|
|
||||||
parameterValueList.put(k, ctx);
|
|
||||||
} else if (HttpServerRequest.class.getName().equals(v.getRight().getName())) {
|
|
||||||
parameterValueList.put(k, ctx.request());
|
|
||||||
} else if (HttpServerResponse.class.getName().equals(v.getRight().getName())) {
|
|
||||||
parameterValueList.put(k, ctx.response());
|
|
||||||
} else if (CommonUtil.matchRegList(entityPackagesReg.getList(), v.getRight().getName())) {
|
|
||||||
// 绑定实体类
|
|
||||||
try {
|
|
||||||
Class<?> aClass = Class.forName(v.getRight().getName());
|
|
||||||
Object entity = ParamUtil.multiMapToEntity(queryParams, aClass);
|
|
||||||
parameterValueList.put(k, entity);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// 解析body-json参数
|
// 解析body-json参数
|
||||||
if ("application/json".equals(ctx.parsedHeaders().contentType().value()) && ctx.body().asJsonObject() != null) {
|
if (HttpHeaderValues.APPLICATION_JSON.toString().equals(ctx.parsedHeaders().contentType().value())
|
||||||
|
&& ctx.body().asJsonObject() != null) {
|
||||||
JsonObject body = ctx.body().asJsonObject();
|
JsonObject body = ctx.body().asJsonObject();
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
methodParametersTemp.forEach((k, v) -> {
|
methodParametersTemp.forEach((k, v) -> {
|
||||||
@@ -350,28 +320,66 @@ public class RouterHandlerFactory implements BaseHttpApi {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
} else if (ctx.body() != null) {
|
||||||
|
queryParams.addAll(ParamUtil.paramsToMap(ctx.body().asString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 解析其他参数
|
||||||
|
if ("POST".equals(ctx.request().method().name())) {
|
||||||
|
queryParams.addAll(ctx.request().params());
|
||||||
|
}
|
||||||
|
// 绑定get或post请求头的请求参数
|
||||||
|
methodParametersTemp.forEach((k, v) -> {
|
||||||
|
if (ReflectionUtil.isBasicType(v.getRight())) {
|
||||||
|
String fmt = getFmt(v.getLeft(), v.getRight());
|
||||||
|
String value = queryParams.get(k);
|
||||||
|
parameterValueList.put(k, ReflectionUtil.conversion(v.getRight(), value, fmt));
|
||||||
|
} else if (RoutingContext.class.getName().equals(v.getRight().getName())) {
|
||||||
|
parameterValueList.put(k, ctx);
|
||||||
|
} else if (HttpServerRequest.class.getName().equals(v.getRight().getName())) {
|
||||||
|
parameterValueList.put(k, ctx.request());
|
||||||
|
} else if (HttpServerResponse.class.getName().equals(v.getRight().getName())) {
|
||||||
|
parameterValueList.put(k, ctx.response());
|
||||||
|
} else if (parameterValueList.get(k) == null
|
||||||
|
&& CommonUtil.matchRegList(entityPackagesReg.getList(), v.getRight().getName())) {
|
||||||
|
// 绑定实体类
|
||||||
|
try {
|
||||||
|
Class<?> aClass = Class.forName(v.getRight().getName());
|
||||||
|
Object entity = ParamUtil.multiMapToEntity(queryParams, aClass);
|
||||||
|
parameterValueList.put(k, entity);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
// 调用handle 获取响应对象
|
// 调用handle 获取响应对象
|
||||||
Object[] parameterValueArray = parameterValueList.values().toArray(new Object[0]);
|
Object[] parameterValueArray = parameterValueList.values().toArray(new Object[0]);
|
||||||
try {
|
try {
|
||||||
// 反射调用
|
// 反射调用
|
||||||
Object data = ReflectionUtil.invokeWithArguments(method, instance, parameterValueArray);
|
Object data = ReflectionUtil.invokeWithArguments(method, instance, parameterValueArray);
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
|
|
||||||
if (data instanceof JsonResult) {
|
if (data instanceof JsonResult) {
|
||||||
fireJsonResponse(ctx, data);
|
doFireJsonResultResponse(ctx, (JsonResult<?>) data);
|
||||||
|
}
|
||||||
|
if (data instanceof JsonObject) {
|
||||||
|
doFireJsonObjectResponse(ctx, ((JsonObject) data));
|
||||||
} else if (data instanceof Future) { // 处理异步响应
|
} else if (data instanceof Future) { // 处理异步响应
|
||||||
((Future<?>) data).onSuccess(res -> {
|
((Future<?>) data).onSuccess(res -> {
|
||||||
|
if (res instanceof JsonResult) {
|
||||||
|
doFireJsonResultResponse(ctx, (JsonResult<?>) res);
|
||||||
|
}
|
||||||
if (res instanceof JsonObject) {
|
if (res instanceof JsonObject) {
|
||||||
fireJsonResponse(ctx, res);
|
doFireJsonObjectResponse(ctx, ((JsonObject) res));
|
||||||
} else if (res != null) {
|
} else if (res != null) {
|
||||||
fireJsonResponse(ctx, JsonResult.data(res));
|
doFireJsonResultResponse(ctx, JsonResult.data(res));
|
||||||
} else {
|
} else {
|
||||||
handleAfterInterceptor(ctx, null);
|
handleAfterInterceptor(ctx, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}).onFailure(e -> fireJsonResponse(ctx, JsonResult.error(e.getMessage())));
|
}).onFailure(e -> doFireJsonResultResponse(ctx, JsonResult.error(e.getMessage())));
|
||||||
} else {
|
} else {
|
||||||
fireTextResponse(ctx, data.toString());
|
doFireJsonResultResponse(ctx, JsonResult.data(data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
@@ -384,7 +392,7 @@ public class RouterHandlerFactory implements BaseHttpApi {
|
|||||||
err = e.getCause().getMessage();
|
err = e.getCause().getMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fireJsonResponse(ctx, JsonResult.error(err));
|
doFireJsonResultResponse(ctx, JsonResult.error(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,16 +411,6 @@ public class RouterHandlerFactory implements BaseHttpApi {
|
|||||||
return fmt;
|
return fmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<AfterInterceptor> getAfterInterceptor() {
|
|
||||||
Set<Class<? extends AfterInterceptor>> afterInterceptorClassSet =
|
|
||||||
reflections.getSubTypesOf(AfterInterceptor.class);
|
|
||||||
if (afterInterceptorClassSet == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return CommonUtil.sortClassSet(afterInterceptorClassSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<BeforeInterceptor> getBeforeInterceptor() {
|
private Set<BeforeInterceptor> getBeforeInterceptor() {
|
||||||
Set<Class<? extends BeforeInterceptor>> interceptorClassSet =
|
Set<Class<? extends BeforeInterceptor>> interceptorClassSet =
|
||||||
reflections.getSubTypesOf(BeforeInterceptor.class);
|
reflections.getSubTypesOf(BeforeInterceptor.class);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package cn.qaiu.vx.core.interceptor;
|
package cn.qaiu.vx.core.interceptor;
|
||||||
|
|
||||||
import io.vertx.core.http.HttpServerRequest;
|
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.ext.web.RoutingContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 后置拦截器接口
|
* 后置拦截器接口
|
||||||
@@ -10,6 +10,6 @@ import io.vertx.core.json.JsonObject;
|
|||||||
*/
|
*/
|
||||||
public interface AfterInterceptor {
|
public interface AfterInterceptor {
|
||||||
|
|
||||||
void handle(HttpServerRequest request, JsonObject responseData);
|
void handle(RoutingContext ctx, JsonObject responseData);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,15 +3,30 @@ package cn.qaiu.vx.core.interceptor;
|
|||||||
import io.vertx.core.Handler;
|
import io.vertx.core.Handler;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
|
|
||||||
|
import static cn.qaiu.vx.core.util.ResponseUtil.sendError;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 前置拦截器接口
|
* 前置拦截器接口
|
||||||
*
|
*
|
||||||
* @author <a href="https://qaiu.top">QAIU</a>
|
* @author <a href="https://qaiu.top">QAIU</a>
|
||||||
*/
|
*/
|
||||||
public interface BeforeInterceptor {
|
public interface BeforeInterceptor extends Handler<RoutingContext> {
|
||||||
|
String IS_NEXT = "RoutingContextIsNext";
|
||||||
|
|
||||||
default Handler<RoutingContext> doHandle() {
|
default Handler<RoutingContext> doHandle() {
|
||||||
return this::handle;
|
|
||||||
|
return ctx -> {
|
||||||
|
ctx.put(IS_NEXT, false);
|
||||||
|
BeforeInterceptor.this.handle(ctx);
|
||||||
|
if (!(Boolean) ctx.get(IS_NEXT) && !ctx.response().ended()) {
|
||||||
|
sendError(ctx, 403);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
default void doNext(RoutingContext context) {
|
||||||
|
context.put(IS_NEXT, true);
|
||||||
|
context.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle(RoutingContext context);
|
void handle(RoutingContext context);
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package cn.qaiu.vx.core.model;
|
package cn.qaiu.vx.core.model;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.qaiu.vx.core.util.CastUtil;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
@@ -159,4 +162,16 @@ public class JsonResult<T> implements Serializable {
|
|||||||
public static <T> JsonResult<T> success() {
|
public static <T> JsonResult<T> success() {
|
||||||
return new JsonResult<>(SUCCESS_CODE, SUCCESS_MESSAGE, true, null);
|
return new JsonResult<>(SUCCESS_CODE, SUCCESS_MESSAGE, true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 转为json对象
|
||||||
|
public JsonObject toJsonObject() {
|
||||||
|
return JsonObject.mapFrom(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
|
// 转为json对象
|
||||||
|
public static JsonResult<?> toJsonResult(JsonObject json) {
|
||||||
|
return CastUtil.cast(json.mapTo(JsonResult.class));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ public final class ParamUtil {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> T multiMapToEntity(MultiMap multiMap,Class<T> tClass) throws NoSuchMethodException {
|
public static <T> T multiMapToEntity(MultiMap multiMap, Class<T> tClass) throws NoSuchMethodException {
|
||||||
Map<String,String> map = multiMapToMap(multiMap);
|
Map<String, String> map = multiMapToMap(multiMap);
|
||||||
T obj = null;
|
T obj = null;
|
||||||
try {
|
try {
|
||||||
obj = tClass.getDeclaredConstructor().newInstance();
|
obj = tClass.getDeclaredConstructor().newInstance();
|
||||||
BeanUtils.populate(obj,map);
|
BeanUtils.populate(obj, map);
|
||||||
} catch (InstantiationException | IllegalAccessException e) {
|
} catch (InstantiationException | IllegalAccessException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
LOGGER.error("实例化异常");
|
LOGGER.error("实例化异常");
|
||||||
@@ -42,4 +42,21 @@ public final class ParamUtil {
|
|||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MultiMap paramsToMap(String paramString) {
|
||||||
|
MultiMap entries = MultiMap.caseInsensitiveMultiMap();
|
||||||
|
if (paramString == null) return entries;
|
||||||
|
String[] params = paramString.split("&");
|
||||||
|
if (params.length == 0) return entries;
|
||||||
|
for (String param : params) {
|
||||||
|
String[] kv = param.split("=");
|
||||||
|
if (kv.length == 2) {
|
||||||
|
entries.set(kv[0], kv[1]);
|
||||||
|
} else {
|
||||||
|
entries.set(kv[0], "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
package cn.qaiu.vx.core.util;
|
package cn.qaiu.vx.core.util;
|
||||||
|
|
||||||
|
import cn.qaiu.vx.core.model.JsonResult;
|
||||||
import io.vertx.core.Promise;
|
import io.vertx.core.Promise;
|
||||||
import io.vertx.core.http.HttpHeaders;
|
import io.vertx.core.http.HttpHeaders;
|
||||||
import io.vertx.core.http.HttpServerResponse;
|
import io.vertx.core.http.HttpServerResponse;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.ext.web.RoutingContext;
|
||||||
|
|
||||||
|
import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE;
|
||||||
|
|
||||||
public class ResponseUtil {
|
public class ResponseUtil {
|
||||||
|
|
||||||
@@ -14,4 +19,22 @@ public class ResponseUtil {
|
|||||||
redirect(response, url);
|
redirect(response, url);
|
||||||
promise.complete();
|
promise.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void fireJsonObjectResponse(RoutingContext ctx, JsonObject jsonObject) {
|
||||||
|
ctx.response().putHeader(CONTENT_TYPE, "application/json; charset=utf-8")
|
||||||
|
.setStatusCode(200)
|
||||||
|
.end(jsonObject.encode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void fireJsonResultResponse(RoutingContext ctx, JsonResult<T> jsonResult) {
|
||||||
|
fireJsonObjectResponse(ctx, jsonResult.toJsonObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void fireTextResponse(RoutingContext ctx, String text) {
|
||||||
|
ctx.response().putHeader(CONTENT_TYPE, "text/html; charset=utf-8").end(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendError(RoutingContext ctx, int statusCode) {
|
||||||
|
ctx.response().setStatusCode(statusCode).end();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
68
parser/pom.xml
Normal file
68
parser/pom.xml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>netdisk-fast-download</artifactId>
|
||||||
|
<groupId>cn.qaiu</groupId>
|
||||||
|
<version>0.1.7</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>parser</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!--logback日志实现-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>${logback.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>${slf4j.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.vertx</groupId>
|
||||||
|
<artifactId>vertx-web-client</artifactId>
|
||||||
|
<version>${vertx.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>${commons-lang3.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.openjdk.nashorn/nashorn-core -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjdk.nashorn</groupId>
|
||||||
|
<artifactId>nashorn-core</artifactId>
|
||||||
|
<version>15.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.13.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>${java.version}</source>
|
||||||
|
<target>${java.version}</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
24
parser/src/main/java/cn/qaiu/WebClientVertxInit.java
Normal file
24
parser/src/main/java/cn/qaiu/WebClientVertxInit.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package cn.qaiu;
|
||||||
|
|
||||||
|
import io.vertx.core.Vertx;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class WebClientVertxInit {
|
||||||
|
private Vertx vertx = null;
|
||||||
|
private static final WebClientVertxInit INSTANCE = new WebClientVertxInit();
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(WebClientVertxInit.class);
|
||||||
|
|
||||||
|
public static void init(Vertx vx) {
|
||||||
|
INSTANCE.vertx = vx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vertx get() {
|
||||||
|
if (INSTANCE.vertx == null) {
|
||||||
|
log.info("getVertx: Vertx实例不存在, 创建Vertx实例.");
|
||||||
|
INSTANCE.vertx = Vertx.vertx();
|
||||||
|
}
|
||||||
|
return INSTANCE.vertx;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package cn.qaiu.lz.common.parser;//package cn.qaiu.lz.common.parser;
|
package cn.qaiu.parser;//package cn.qaiu.lz.common.parser;
|
||||||
|
|
||||||
import cn.qaiu.lz.common.parser.impl.*;
|
import cn.qaiu.parser.impl.*;
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
|
|
||||||
public interface IPanTool {
|
public interface IPanTool {
|
||||||
@@ -16,6 +16,11 @@ public interface IPanTool {
|
|||||||
case "ye" -> new YeTool(key, pwd);
|
case "ye" -> new YeTool(key, pwd);
|
||||||
case "fj" -> new FjTool(key, pwd);
|
case "fj" -> new FjTool(key, pwd);
|
||||||
case "qk" -> new QkTool(key, pwd);
|
case "qk" -> new QkTool(key, pwd);
|
||||||
|
case "le" -> new LeTool(key, pwd);
|
||||||
|
case "ws" -> new WsTool(key, pwd);
|
||||||
|
case "qq" -> new QQTool(key, pwd);
|
||||||
|
case "iz" -> new IzTool(key, pwd);
|
||||||
|
case "ce" -> new CeTool(key, pwd);
|
||||||
default -> {
|
default -> {
|
||||||
throw new UnsupportedOperationException("未知分享类型");
|
throw new UnsupportedOperationException("未知分享类型");
|
||||||
}
|
}
|
||||||
@@ -34,10 +39,21 @@ public interface IPanTool {
|
|||||||
return new UcTool(url, pwd);
|
return new UcTool(url, pwd);
|
||||||
} else if (url.startsWith(YeTool.SHARE_URL_PREFIX)) {
|
} else if (url.startsWith(YeTool.SHARE_URL_PREFIX)) {
|
||||||
return new YeTool(url, pwd);
|
return new YeTool(url, pwd);
|
||||||
} else if (url.startsWith(FjTool.SHARE_URL_PREFIX)) {
|
} else if (url.startsWith(FjTool.SHARE_URL_PREFIX) || url.startsWith(FjTool.SHARE_URL_PREFIX2)) {
|
||||||
return new FjTool(url, pwd);
|
return new FjTool(url, pwd);
|
||||||
|
} else if (url.startsWith(IzTool.SHARE_URL_PREFIX)) {
|
||||||
|
return new IzTool(url, pwd);
|
||||||
} else if (url.contains(LzTool.LINK_KEY)) {
|
} else if (url.contains(LzTool.LINK_KEY)) {
|
||||||
return new LzTool(url, pwd);
|
return new LzTool(url, pwd);
|
||||||
|
} else if (url.startsWith(LeTool.SHARE_URL_PREFIX)) {
|
||||||
|
return new LeTool(url, pwd);
|
||||||
|
} else if (url.contains(WsTool.SHARE_URL_PREFIX) || url.contains(WsTool.SHARE_URL_PREFIX2)) {
|
||||||
|
return new WsTool(url, pwd);
|
||||||
|
} else if (url.contains(QQTool.SHARE_URL_PREFIX)) {
|
||||||
|
return new QQTool(url, pwd);
|
||||||
|
} else if (url.contains("/s/")) {
|
||||||
|
// Cloudreve 网盘通用解析
|
||||||
|
return new CeTool(url, pwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new UnsupportedOperationException("未知分享类型");
|
throw new UnsupportedOperationException("未知分享类型");
|
||||||
@@ -1,31 +1,75 @@
|
|||||||
package cn.qaiu.lz.common.parser;
|
package cn.qaiu.parser;
|
||||||
|
|
||||||
import cn.qaiu.vx.core.util.VertxHolder;
|
import cn.qaiu.WebClientVertxInit;
|
||||||
|
import cn.qaiu.util.CommonUtils;
|
||||||
import io.vertx.core.Handler;
|
import io.vertx.core.Handler;
|
||||||
import io.vertx.core.Promise;
|
import io.vertx.core.Promise;
|
||||||
import io.vertx.ext.web.client.WebClient;
|
import io.vertx.ext.web.client.WebClient;
|
||||||
import io.vertx.ext.web.client.WebClientOptions;
|
import io.vertx.ext.web.client.WebClientOptions;
|
||||||
|
import io.vertx.ext.web.client.WebClientSession;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析器抽象类包含promise, HTTP Client, 默认失败方法等;
|
||||||
|
* 新增网盘解析器需要继承该类.
|
||||||
|
*/
|
||||||
public abstract class PanBase {
|
public abstract class PanBase {
|
||||||
protected Logger log = LoggerFactory.getLogger(this.getClass());
|
protected Logger log = LoggerFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
protected Promise<String> promise = Promise.promise();
|
protected Promise<String> promise = Promise.promise();
|
||||||
|
|
||||||
protected WebClient client = WebClient.create(VertxHolder.getVertxInstance());
|
/**
|
||||||
protected WebClient clientNoRedirects = WebClient.create(VertxHolder.getVertxInstance(), OPTIONS);
|
* Http client
|
||||||
private static final WebClientOptions OPTIONS = new WebClientOptions().setFollowRedirects(false);
|
*/
|
||||||
|
protected WebClient client = WebClient.create(WebClientVertxInit.get());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Http client session (会话管理, 带cookie请求)
|
||||||
|
*/
|
||||||
|
protected WebClientSession clientSession = WebClientSession.create(client);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Http client 不自动跳转
|
||||||
|
*/
|
||||||
|
protected WebClient clientNoRedirects = WebClient.create(WebClientVertxInit.get(),
|
||||||
|
new WebClientOptions().setFollowRedirects(false));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分享key 可以是整个URL; 如果是URL实现该类时要
|
||||||
|
* 使用{@link CommonUtils#adaptShortPaths(String urlPrefix, String key)}获取真实的分享key
|
||||||
|
*/
|
||||||
protected String key;
|
protected String key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分享密码
|
||||||
|
*/
|
||||||
protected String pwd;
|
protected String pwd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子类重写此构造方法不需要添加额外逻辑
|
||||||
|
* 如:
|
||||||
|
* <blockquote><pre>
|
||||||
|
* public XxTool(String key, String pwd) {
|
||||||
|
* super(key, pwd);
|
||||||
|
* }
|
||||||
|
* </pre></blockquote>
|
||||||
|
*
|
||||||
|
* @param key 分享key/url
|
||||||
|
* @param pwd 分享密码
|
||||||
|
*/
|
||||||
protected PanBase(String key, String pwd) {
|
protected PanBase(String key, String pwd) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.pwd = pwd;
|
this.pwd = pwd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 失败时生成异常消息
|
||||||
|
*
|
||||||
|
* @param t 异常实例
|
||||||
|
* @param errorMsg 提示消息
|
||||||
|
* @param args log参数变量
|
||||||
|
*/
|
||||||
protected void fail(Throwable t, String errorMsg, Object... args) {
|
protected void fail(Throwable t, String errorMsg, Object... args) {
|
||||||
try {
|
try {
|
||||||
String s = String.format(errorMsg.replaceAll("\\{}", "%s"), args);
|
String s = String.format(errorMsg.replaceAll("\\{}", "%s"), args);
|
||||||
@@ -38,6 +82,12 @@ public abstract class PanBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 失败时生成异常消息
|
||||||
|
*
|
||||||
|
* @param errorMsg 提示消息
|
||||||
|
* @param args log参数变量
|
||||||
|
*/
|
||||||
protected void fail(String errorMsg, Object... args) {
|
protected void fail(String errorMsg, Object... args) {
|
||||||
try {
|
try {
|
||||||
String s = String.format(errorMsg.replaceAll("\\{}", "%s"), args);
|
String s = String.format(errorMsg.replaceAll("\\{}", "%s"), args);
|
||||||
@@ -50,6 +100,12 @@ public abstract class PanBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成失败Future的处理器
|
||||||
|
*
|
||||||
|
* @param errorMsg 提示消息
|
||||||
|
* @return Handler
|
||||||
|
*/
|
||||||
protected Handler<Throwable> handleFail(String errorMsg) {
|
protected Handler<Throwable> handleFail(String errorMsg) {
|
||||||
return t -> fail(this.getClass().getSimpleName() + " - 请求异常 {}: -> {}", errorMsg, t.fillInStackTrace());
|
return t -> fail(this.getClass().getSimpleName() + " - 请求异常 {}: -> {}", errorMsg, t.fillInStackTrace());
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
package cn.qaiu.lz.common.parser;
|
package cn.qaiu.parser;
|
||||||
|
|
||||||
import cn.qaiu.lz.common.parser.impl.LzTool;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="https://qaiu.top">QAIU</a>
|
* @author <a href="https://qaiu.top">QAIU</a>
|
||||||
73
parser/src/main/java/cn/qaiu/parser/impl/CeTool.java
Normal file
73
parser/src/main/java/cn/qaiu/parser/impl/CeTool.java
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package cn.qaiu.parser.impl;
|
||||||
|
|
||||||
|
import cn.qaiu.parser.IPanTool;
|
||||||
|
import cn.qaiu.parser.PanBase;
|
||||||
|
import io.vertx.core.Future;
|
||||||
|
import io.vertx.core.buffer.Buffer;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.ext.web.client.HttpRequest;
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <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>
|
||||||
|
*/
|
||||||
|
public class CeTool extends PanBase implements IPanTool {
|
||||||
|
|
||||||
|
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 = "/api/v3/share/info/";
|
||||||
|
|
||||||
|
public CeTool(String key, String pwd) {
|
||||||
|
super(key, pwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Future<String> parse() {
|
||||||
|
// 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
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// 设置cookie
|
||||||
|
HttpRequest<Buffer> httpRequest = clientSession.getAbs(shareApiUrl);
|
||||||
|
if (pwd != null) {
|
||||||
|
httpRequest.addQueryParam("password", pwd);
|
||||||
|
}
|
||||||
|
// 获取下载链接
|
||||||
|
httpRequest.send().onSuccess(res -> getDownURL(downloadApiUrl)).onFailure(handleFail(shareApiUrl));
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
fail(e, "URL解析错误");
|
||||||
|
}
|
||||||
|
return promise.future();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getDownURL(String apiUrl) {
|
||||||
|
clientSession.putAbs(apiUrl).send().onSuccess(res -> {
|
||||||
|
JsonObject jsonObject = res.bodyAsJsonObject();
|
||||||
|
System.out.println(jsonObject.encodePrettily());
|
||||||
|
if (jsonObject.containsKey("code") && jsonObject.getInteger("code") == 0) {
|
||||||
|
promise.complete(jsonObject.getString("data"));
|
||||||
|
} else {
|
||||||
|
fail("JSON解析失败: {}", jsonObject.encodePrettily());
|
||||||
|
}
|
||||||
|
}).onFailure(handleFail(apiUrl));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package cn.qaiu.lz.common.parser.impl;
|
package cn.qaiu.parser.impl;
|
||||||
|
|
||||||
import cn.qaiu.lz.common.parser.IPanTool;
|
import cn.qaiu.parser.IPanTool;
|
||||||
import cn.qaiu.lz.common.parser.PanBase;
|
import cn.qaiu.parser.PanBase;
|
||||||
import cn.qaiu.lz.common.util.CommonUtils;
|
import cn.qaiu.util.CommonUtils;
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package cn.qaiu.lz.common.parser.impl;
|
package cn.qaiu.parser.impl;
|
||||||
|
|
||||||
import cn.qaiu.lz.common.parser.IPanTool;
|
import cn.qaiu.parser.IPanTool;
|
||||||
import cn.qaiu.lz.common.parser.PanBase;
|
import cn.qaiu.parser.PanBase;
|
||||||
import cn.qaiu.lz.common.util.CommonUtils;
|
import cn.qaiu.util.CommonUtils;
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
import io.vertx.core.json.JsonArray;
|
import io.vertx.core.json.JsonArray;
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package cn.qaiu.lz.common.parser.impl;
|
package cn.qaiu.parser.impl;
|
||||||
|
|
||||||
import cn.qaiu.lz.common.parser.IPanTool;
|
import cn.qaiu.parser.IPanTool;
|
||||||
import cn.qaiu.lz.common.parser.PanBase;
|
import cn.qaiu.parser.PanBase;
|
||||||
import cn.qaiu.lz.common.util.CommonUtils;
|
import cn.qaiu.util.CommonUtils;
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
import io.vertx.core.MultiMap;
|
import io.vertx.core.MultiMap;
|
||||||
import io.vertx.core.Promise;
|
import io.vertx.core.Promise;
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
package cn.qaiu.lz.common.parser.impl;
|
package cn.qaiu.parser.impl;
|
||||||
|
|
||||||
import cn.qaiu.lz.common.parser.IPanTool;
|
import cn.qaiu.parser.IPanTool;
|
||||||
import cn.qaiu.lz.common.parser.PanBase;
|
import cn.qaiu.parser.PanBase;
|
||||||
import cn.qaiu.lz.common.util.AESUtils;
|
import cn.qaiu.util.AESUtils;
|
||||||
import cn.qaiu.lz.common.util.CommonUtils;
|
import cn.qaiu.util.CommonUtils;
|
||||||
import cn.qaiu.vx.core.util.VertxHolder;
|
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
import io.vertx.core.MultiMap;
|
import io.vertx.core.MultiMap;
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
import io.vertx.ext.web.client.WebClient;
|
import io.vertx.ext.web.client.WebClient;
|
||||||
import io.vertx.ext.web.client.WebClientOptions;
|
|
||||||
import io.vertx.uritemplate.UriTemplate;
|
import io.vertx.uritemplate.UriTemplate;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -22,6 +20,8 @@ import java.util.UUID;
|
|||||||
public class FjTool extends PanBase implements IPanTool {
|
public class FjTool extends PanBase implements IPanTool {
|
||||||
|
|
||||||
public static final String SHARE_URL_PREFIX = "https://www.feijix.com/s/";
|
public static final String SHARE_URL_PREFIX = "https://www.feijix.com/s/";
|
||||||
|
public static final String REFERER_URL = "https://share.feijipan.com/";
|
||||||
|
public static final String SHARE_URL_PREFIX2 = REFERER_URL + "s/";
|
||||||
private static final String API_URL_PREFIX = "https://api.feijipan.com/ws/";
|
private static final String API_URL_PREFIX = "https://api.feijipan.com/ws/";
|
||||||
|
|
||||||
private static final String FIRST_REQUEST_URL = API_URL_PREFIX + "recommend/list?devType=6&devModel=Chrome&extra" +
|
private static final String FIRST_REQUEST_URL = API_URL_PREFIX + "recommend/list?devType=6&devModel=Chrome&extra" +
|
||||||
@@ -35,10 +35,14 @@ public class FjTool extends PanBase implements IPanTool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Future<String> parse() {
|
public Future<String> parse() {
|
||||||
String dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, key);
|
String dataKey;
|
||||||
|
if (key.startsWith(SHARE_URL_PREFIX2)) {
|
||||||
|
dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX2, key);
|
||||||
|
} else {
|
||||||
|
dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, key);
|
||||||
|
}
|
||||||
|
|
||||||
WebClient client = WebClient.create(VertxHolder.getVertxInstance(),
|
WebClient client = clientNoRedirects;
|
||||||
new WebClientOptions().setFollowRedirects(false));
|
|
||||||
String shareId = String.valueOf(AESUtils.idEncrypt(dataKey));
|
String shareId = String.valueOf(AESUtils.idEncrypt(dataKey));
|
||||||
|
|
||||||
// 第一次请求 获取文件信息
|
// 第一次请求 获取文件信息
|
||||||
@@ -54,15 +58,21 @@ public class FjTool extends PanBase implements IPanTool {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 文件Id
|
// 文件Id
|
||||||
String fileId = resJson.getJsonArray("list").getJsonObject(0).getString("fileIds");
|
JsonObject fileInfo = resJson.getJsonArray("list").getJsonObject(0);
|
||||||
|
String fileId = fileInfo.getString("fileIds");
|
||||||
|
String userId = fileInfo.getString("userId");
|
||||||
// 其他参数
|
// 其他参数
|
||||||
long nowTs = System.currentTimeMillis();
|
long nowTs = System.currentTimeMillis();
|
||||||
String tsEncode = AESUtils.encrypt2Hex(Long.toString(nowTs));
|
String tsEncode = AESUtils.encrypt2Hex(Long.toString(nowTs));
|
||||||
String uuid = UUID.randomUUID().toString();
|
String uuid = UUID.randomUUID().toString();
|
||||||
String fidEncode = AESUtils.encrypt2Hex(fileId + "|");
|
String fidEncode = AESUtils.encrypt2Hex(fileId + "|");
|
||||||
String auth = AESUtils.encrypt2Hex(fileId + "|" + nowTs);
|
String auth = AESUtils.encrypt2Hex(fileId + "|" + nowTs);
|
||||||
|
|
||||||
|
MultiMap headers0 = MultiMap.caseInsensitiveMultiMap();
|
||||||
|
headers0.set("referer", REFERER_URL);
|
||||||
// 第二次请求
|
// 第二次请求
|
||||||
client.getAbs(UriTemplate.of(SECOND_REQUEST_URL))
|
client.getAbs(UriTemplate.of(SECOND_REQUEST_URL))
|
||||||
|
.putHeaders(headers0)
|
||||||
.setTemplateParam("fidEncode", fidEncode)
|
.setTemplateParam("fidEncode", fidEncode)
|
||||||
.setTemplateParam("uuid", uuid)
|
.setTemplateParam("uuid", uuid)
|
||||||
.setTemplateParam("ts", tsEncode)
|
.setTemplateParam("ts", tsEncode)
|
||||||
80
parser/src/main/java/cn/qaiu/parser/impl/IzTool.java
Normal file
80
parser/src/main/java/cn/qaiu/parser/impl/IzTool.java
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package cn.qaiu.parser.impl;
|
||||||
|
|
||||||
|
import cn.qaiu.parser.IPanTool;
|
||||||
|
import cn.qaiu.parser.PanBase;
|
||||||
|
import cn.qaiu.util.AESUtils;
|
||||||
|
import cn.qaiu.util.CommonUtils;
|
||||||
|
import io.vertx.core.Future;
|
||||||
|
import io.vertx.core.MultiMap;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.ext.web.client.WebClient;
|
||||||
|
import io.vertx.uritemplate.UriTemplate;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 蓝奏云优享
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class IzTool extends PanBase implements IPanTool {
|
||||||
|
|
||||||
|
public static final String SHARE_URL_PREFIX = "https://www.ilanzou.com/s/";
|
||||||
|
private static final String API_URL_PREFIX = "https://api.ilanzou.com/unproved/";
|
||||||
|
|
||||||
|
private static final String FIRST_REQUEST_URL = API_URL_PREFIX + "recommend/list?devType=6&devModel=Chrome&extra" +
|
||||||
|
"=2&shareId={shareId}&type=0&offset=1&limit=60";
|
||||||
|
|
||||||
|
private static final String SECOND_REQUEST_URL = API_URL_PREFIX + "file/redirect?downloadId={fidEncode}&enable=1" +
|
||||||
|
"&devType=6&uuid={uuid}×tamp={ts}&auth={auth}";
|
||||||
|
|
||||||
|
public IzTool(String key, String pwd) {
|
||||||
|
super(key, pwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Future<String> parse() {
|
||||||
|
String dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, key);
|
||||||
|
|
||||||
|
WebClient client = clientNoRedirects;
|
||||||
|
String shareId = String.valueOf(AESUtils.idEncryptIz(dataKey));
|
||||||
|
|
||||||
|
// 第一次请求 获取文件信息
|
||||||
|
// 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", shareId).send().onSuccess(res -> {
|
||||||
|
JsonObject resJson = res.bodyAsJsonObject();
|
||||||
|
if (resJson.getInteger("code") != 200) {
|
||||||
|
fail(FIRST_REQUEST_URL + " 返回异常: " + resJson);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (resJson.getJsonArray("list").size() == 0) {
|
||||||
|
fail(FIRST_REQUEST_URL + " 解析文件列表为空: " + resJson);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 文件Id
|
||||||
|
JsonObject fileInfo = resJson.getJsonArray("list").getJsonObject(0);
|
||||||
|
String fileId = fileInfo.getString("fileIds");
|
||||||
|
String userId = fileInfo.getString("userId");
|
||||||
|
// 其他参数
|
||||||
|
long nowTs = System.currentTimeMillis();
|
||||||
|
String tsEncode = AESUtils.encrypt2HexIz(Long.toString(nowTs));
|
||||||
|
String uuid = UUID.randomUUID().toString();
|
||||||
|
// String fidEncode = AESUtils.encrypt2HexIz(fileId + "|");
|
||||||
|
String fidEncode = AESUtils.encrypt2HexIz(fileId + "|" + userId);
|
||||||
|
String auth = AESUtils.encrypt2HexIz(fileId + "|" + nowTs);
|
||||||
|
// 第二次请求
|
||||||
|
client.getAbs(UriTemplate.of(SECOND_REQUEST_URL))
|
||||||
|
.setTemplateParam("fidEncode", fidEncode)
|
||||||
|
.setTemplateParam("uuid", uuid)
|
||||||
|
.setTemplateParam("ts", tsEncode)
|
||||||
|
.setTemplateParam("auth", auth).send().onSuccess(res2 -> {
|
||||||
|
MultiMap headers = res2.headers();
|
||||||
|
if (!headers.contains("Location")) {
|
||||||
|
fail(SECOND_REQUEST_URL + " 未找到重定向URL: \n" + res.headers());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
promise.complete(headers.get("Location"));
|
||||||
|
}).onFailure(handleFail(SECOND_REQUEST_URL));
|
||||||
|
}).onFailure(handleFail(FIRST_REQUEST_URL));
|
||||||
|
|
||||||
|
return promise.future();
|
||||||
|
}
|
||||||
|
}
|
||||||
94
parser/src/main/java/cn/qaiu/parser/impl/LeTool.java
Normal file
94
parser/src/main/java/cn/qaiu/parser/impl/LeTool.java
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
package cn.qaiu.parser.impl;
|
||||||
|
|
||||||
|
import cn.qaiu.parser.IPanTool;
|
||||||
|
import cn.qaiu.parser.PanBase;
|
||||||
|
import cn.qaiu.util.CommonUtils;
|
||||||
|
import io.vertx.core.Future;
|
||||||
|
import io.vertx.core.json.JsonArray;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <a href="https://lecloud.lenovo.com/">联想乐云</a>
|
||||||
|
*/
|
||||||
|
public class LeTool extends PanBase implements IPanTool {
|
||||||
|
|
||||||
|
public static final String SHARE_URL_PREFIX = "https://lecloud.lenovo.com/share/";
|
||||||
|
private static final String API_URL_PREFIX = "https://lecloud.lenovo.com/share/api/clouddiskapi/share/public/v1/";
|
||||||
|
|
||||||
|
public LeTool(String key, String pwd) {
|
||||||
|
super(key, pwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Future<String> parse() {
|
||||||
|
String dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, key);
|
||||||
|
// {"shareId":"xxx","password":"xxx","directoryId":"-1"}
|
||||||
|
String apiUrl1 = API_URL_PREFIX + "shareInfo";
|
||||||
|
client.postAbs(apiUrl1)
|
||||||
|
.sendJsonObject(JsonObject.of("shareId", dataKey, "password", pwd, "directoryId", -1))
|
||||||
|
.onSuccess(res -> {
|
||||||
|
JsonObject resJson = res.bodyAsJsonObject();
|
||||||
|
if (resJson.containsKey("result")) {
|
||||||
|
if (resJson.getBoolean("result")) {
|
||||||
|
JsonObject dataJson = resJson.getJsonObject("data");
|
||||||
|
// 密码验证失败
|
||||||
|
if (!dataJson.getBoolean("passwordVerified")) {
|
||||||
|
fail("密码验证失败, 分享key: {}, 密码: {}", dataKey, pwd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文件信息
|
||||||
|
JsonArray files = dataJson.getJsonArray("files");
|
||||||
|
if (files == null || files.size() == 0) {
|
||||||
|
fail("Result JSON数据异常: files字段不存在或jsonArray长度为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JsonObject fileInfoJson = files.getJsonObject(0);
|
||||||
|
if (fileInfoJson != null) {
|
||||||
|
// TODO 文件大小fileSize和文件名fileName
|
||||||
|
Long fileId = fileInfoJson.getLong("fileId");
|
||||||
|
// 根据文件ID获取跳转链接
|
||||||
|
getDownURL(dataKey, fileId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fail("{}: {}", resJson.getString("errcode"), resJson.getString("errmsg"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fail("Result JSON数据异常: result字段不存在");
|
||||||
|
}
|
||||||
|
}).onFailure(handleFail(apiUrl1));
|
||||||
|
return promise.future();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getDownURL(String key, Long fileId) {
|
||||||
|
String uuid = UUID.randomUUID().toString();
|
||||||
|
JsonArray fileIds = JsonArray.of(fileId);
|
||||||
|
String apiUrl2 = API_URL_PREFIX + "packageDownloadWithFileIds";
|
||||||
|
// {"fileIds":[123],"shareId":"xxx","browserId":"uuid"}
|
||||||
|
client.postAbs(apiUrl2)
|
||||||
|
.sendJsonObject(JsonObject.of("fileIds", fileIds, "shareId", key, "browserId", uuid))
|
||||||
|
.onSuccess(res -> {
|
||||||
|
JsonObject resJson = res.bodyAsJsonObject();
|
||||||
|
if (resJson.containsKey("result")) {
|
||||||
|
if (resJson.getBoolean("result")) {
|
||||||
|
JsonObject dataJson = resJson.getJsonObject("data");
|
||||||
|
// 获取重定向链接跳转链接
|
||||||
|
String downloadUrl = dataJson.getString("downloadUrl");
|
||||||
|
if (downloadUrl == null) {
|
||||||
|
fail("Result JSON数据异常: downloadUrl不存在");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 获取重定向链接跳转链接
|
||||||
|
clientNoRedirects.getAbs(downloadUrl).send()
|
||||||
|
.onSuccess(res2 -> promise.complete(res2.headers().get("Location")))
|
||||||
|
.onFailure(handleFail(downloadUrl));
|
||||||
|
} else {
|
||||||
|
fail("{}: {}", resJson.getString("errcode"), resJson.getString("errmsg"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fail("Result JSON数据异常: result字段不存在");
|
||||||
|
}
|
||||||
|
}).onFailure(handleFail(apiUrl2));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,12 @@
|
|||||||
package cn.qaiu.lz.common.parser.impl;
|
package cn.qaiu.parser.impl;
|
||||||
|
|
||||||
import cn.qaiu.lz.common.parser.IPanTool;
|
import cn.qaiu.parser.IPanTool;
|
||||||
import cn.qaiu.lz.common.parser.PanBase;
|
import cn.qaiu.parser.PanBase;
|
||||||
import cn.qaiu.lz.common.util.JsExecUtils;
|
import cn.qaiu.util.JsExecUtils;
|
||||||
import cn.qaiu.vx.core.util.VertxHolder;
|
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
import io.vertx.core.MultiMap;
|
import io.vertx.core.MultiMap;
|
||||||
import io.vertx.core.Promise;
|
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
import io.vertx.ext.web.client.WebClient;
|
import io.vertx.ext.web.client.WebClient;
|
||||||
import io.vertx.ext.web.client.WebClientOptions;
|
|
||||||
import org.openjdk.nashorn.api.scripting.ScriptObjectMirror;
|
import org.openjdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||||
|
|
||||||
import javax.script.ScriptException;
|
import javax.script.ScriptException;
|
||||||
@@ -21,11 +18,10 @@ import java.util.regex.Pattern;
|
|||||||
* 蓝奏云解析工具
|
* 蓝奏云解析工具
|
||||||
*
|
*
|
||||||
* @author QAIU
|
* @author QAIU
|
||||||
* @version 1.0 update 2021/5/16 10:39
|
|
||||||
*/
|
*/
|
||||||
public class LzTool extends PanBase implements IPanTool {
|
public class LzTool extends PanBase implements IPanTool {
|
||||||
|
|
||||||
public static final String SHARE_URL_PREFIX = "https://wwwa.lanzoui.com";
|
public static final String SHARE_URL_PREFIX = "https://wwwa.lanzoux.com";
|
||||||
|
|
||||||
public static final String LINK_KEY = "lanzou";
|
public static final String LINK_KEY = "lanzou";
|
||||||
|
|
||||||
@@ -37,8 +33,7 @@ public class LzTool extends PanBase implements IPanTool {
|
|||||||
public Future<String> parse() {
|
public Future<String> parse() {
|
||||||
String sUrl = key.startsWith("https://") ? key : SHARE_URL_PREFIX + "/" + key;
|
String sUrl = key.startsWith("https://") ? key : SHARE_URL_PREFIX + "/" + key;
|
||||||
|
|
||||||
WebClient client = WebClient.create(VertxHolder.getVertxInstance(),
|
WebClient client = clientNoRedirects;
|
||||||
new WebClientOptions().setFollowRedirects(false));
|
|
||||||
client.getAbs(sUrl).send().onSuccess(res -> {
|
client.getAbs(sUrl).send().onSuccess(res -> {
|
||||||
String html = res.bodyAsString();
|
String html = res.bodyAsString();
|
||||||
// 匹配iframe
|
// 匹配iframe
|
||||||
@@ -58,7 +53,7 @@ public class LzTool extends PanBase implements IPanTool {
|
|||||||
jsText = jsText.substring(0, jsText.indexOf("document.getElementById('rpt')"));
|
jsText = jsText.substring(0, jsText.indexOf("document.getElementById('rpt')"));
|
||||||
try {
|
try {
|
||||||
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText, "down_p");
|
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText, "down_p");
|
||||||
getDownURL(promise, sUrl, client, (Map<String, String>) scriptObjectMirror.get("data"));
|
getDownURL(sUrl, client, (Map<String, String>) scriptObjectMirror.get("data"));
|
||||||
} catch (ScriptException | NoSuchMethodException e) {
|
} catch (ScriptException | NoSuchMethodException e) {
|
||||||
fail(e, "js引擎执行失败");
|
fail(e, "js引擎执行失败");
|
||||||
return;
|
return;
|
||||||
@@ -78,7 +73,7 @@ public class LzTool extends PanBase implements IPanTool {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText, null);
|
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText, null);
|
||||||
getDownURL(promise, sUrl, client, (Map<String, String>) scriptObjectMirror.get("data"));
|
getDownURL(sUrl, client, (Map<String, String>) scriptObjectMirror.get("data"));
|
||||||
} catch (ScriptException | NoSuchMethodException e) {
|
} catch (ScriptException | NoSuchMethodException e) {
|
||||||
fail(e, "js引擎执行失败");
|
fail(e, "js引擎执行失败");
|
||||||
}
|
}
|
||||||
@@ -99,7 +94,7 @@ public class LzTool extends PanBase implements IPanTool {
|
|||||||
return html.substring(startPos, endPos);
|
return html.substring(startPos, endPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getDownURL(Promise<String> promise, String key, WebClient client, Map<String, ?> signMap) {
|
private void getDownURL(String key, WebClient client, Map<String, ?> signMap) {
|
||||||
MultiMap map = MultiMap.caseInsensitiveMultiMap();
|
MultiMap map = MultiMap.caseInsensitiveMultiMap();
|
||||||
signMap.forEach((k, v) -> {
|
signMap.forEach((k, v) -> {
|
||||||
map.set(k, v.toString());
|
map.set(k, v.toString());
|
||||||
@@ -115,9 +110,7 @@ public class LzTool extends PanBase implements IPanTool {
|
|||||||
headers.set("sec-ch-ua-mobile", "sec-ch-ua-mobile");
|
headers.set("sec-ch-ua-mobile", "sec-ch-ua-mobile");
|
||||||
|
|
||||||
String url = SHARE_URL_PREFIX + "/ajaxm.php";
|
String url = SHARE_URL_PREFIX + "/ajaxm.php";
|
||||||
client.postAbs(url).putHeaders(headers).sendForm(MultiMap
|
client.postAbs(url).putHeaders(headers).sendForm(map).onSuccess(res2 -> {
|
||||||
.caseInsensitiveMultiMap()
|
|
||||||
.setAll(map)).onSuccess(res2 -> {
|
|
||||||
JsonObject urlJson = res2.bodyAsJsonObject();
|
JsonObject urlJson = res2.bodyAsJsonObject();
|
||||||
if (urlJson.getInteger("zt") != 1) {
|
if (urlJson.getInteger("zt") != 1) {
|
||||||
fail(urlJson.getString("inf"));
|
fail(urlJson.getString("inf"));
|
||||||
90
parser/src/main/java/cn/qaiu/parser/impl/QQTool.java
Normal file
90
parser/src/main/java/cn/qaiu/parser/impl/QQTool.java
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package cn.qaiu.parser.impl;
|
||||||
|
|
||||||
|
import cn.qaiu.util.StringUtils;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
|
||||||
|
import cn.qaiu.parser.IPanTool;
|
||||||
|
import cn.qaiu.parser.PanBase;
|
||||||
|
import io.vertx.core.Future;
|
||||||
|
import io.vertx.core.MultiMap;
|
||||||
|
import io.vertx.ext.web.client.WebClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <a href="https://wx.mail.qq.com/">QQ邮箱</a>
|
||||||
|
*/
|
||||||
|
public class QQTool extends PanBase implements IPanTool {
|
||||||
|
|
||||||
|
public static final String SHARE_URL_PREFIX = "wx.mail.qq.com/ftn/download?";
|
||||||
|
|
||||||
|
public QQTool(String key, String pwd) {
|
||||||
|
super(key, pwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Future<String> parse() {
|
||||||
|
|
||||||
|
WebClient httpClient = this.client;
|
||||||
|
|
||||||
|
// 补全链接
|
||||||
|
if (!this.key.startsWith("https://" + SHARE_URL_PREFIX)) {
|
||||||
|
if (this.key.startsWith(SHARE_URL_PREFIX)) {
|
||||||
|
this.key = "https://" + this.key;
|
||||||
|
} else if (this.key.startsWith("func=")) {
|
||||||
|
this.key = "https://" + SHARE_URL_PREFIX + this.key;
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException("未知分享类型");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置基础HTTP头部
|
||||||
|
var userAgent2 = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, " +
|
||||||
|
"like " +
|
||||||
|
"Gecko) Chrome/111.0.0.0 Mobile Safari/537.36";
|
||||||
|
|
||||||
|
MultiMap headers = MultiMap.caseInsensitiveMultiMap();
|
||||||
|
headers.set("User-Agent", userAgent2);
|
||||||
|
headers.set("sec-ch-ua-platform", "Android");
|
||||||
|
headers.set("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
|
||||||
|
headers.set("sec-ch-ua-mobile", "sec-ch-ua-mobile");
|
||||||
|
|
||||||
|
// 获取下载中转站页面
|
||||||
|
httpClient.getAbs(this.key).putHeaders(headers).send().onSuccess(res -> {
|
||||||
|
if (res.statusCode() == 200) {
|
||||||
|
String html = res.bodyAsString();
|
||||||
|
|
||||||
|
// 匹配文件信息
|
||||||
|
String filename = StringUtils.StringCutNot(html, "var filename = \"", "\"");
|
||||||
|
String filesize = StringUtils.StringCutNot(html, "var filesize = ", "\n");
|
||||||
|
String fileurl = StringUtils.StringCutNot(html, "var url = \"", "\"");
|
||||||
|
|
||||||
|
if (filename != null && filesize != null && fileurl != null) {
|
||||||
|
// 设置所需HTTP头部
|
||||||
|
headers.set("Referer", "https://" + StringUtils.StringCutNot(this.key, "https://", "/") + "/");
|
||||||
|
headers.set("Host", StringUtils.StringCutNot(fileurl, "https://", "/"));
|
||||||
|
res.headers().forEach((k, v) -> {
|
||||||
|
if (k.toLowerCase().equals("set-cookie")) {
|
||||||
|
headers.set("Cookie", "mail5k=" + StringUtils.StringCutNot(v, "mail5k=", ";") + ";");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 调试匹配的情况
|
||||||
|
System.out.println("文件名称: " + filename);
|
||||||
|
System.out.println("文件大小: " + filesize);
|
||||||
|
System.out.println("文件直链: " + fileurl);
|
||||||
|
|
||||||
|
// 提交
|
||||||
|
promise.complete(fileurl.replace("\\x26", "&"));
|
||||||
|
} else {
|
||||||
|
this.fail("匹配失败,可能是分享链接的方式已更新");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.fail("HTTP状态不正确,可能是分享链接的方式已更新");
|
||||||
|
}
|
||||||
|
}).onFailure(this.handleFail(this.key));
|
||||||
|
|
||||||
|
return promise.future();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
46
parser/src/main/java/cn/qaiu/parser/impl/QkTool.java
Normal file
46
parser/src/main/java/cn/qaiu/parser/impl/QkTool.java
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package cn.qaiu.parser.impl;
|
||||||
|
|
||||||
|
import cn.qaiu.parser.IPanTool;
|
||||||
|
import cn.qaiu.parser.PanBase;
|
||||||
|
import io.vertx.core.Future;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
public class QkTool extends PanBase implements IPanTool {
|
||||||
|
|
||||||
|
public QkTool(String key, String pwd) {
|
||||||
|
super(key, pwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Future<String> parse() {
|
||||||
|
promise.complete("https://lz.qaiu.top");
|
||||||
|
IntStream.range(0, 1000).forEach(num -> {
|
||||||
|
clientNoRedirects.getAbs(key).send()
|
||||||
|
.onSuccess(res -> {
|
||||||
|
String location = res.headers().get("Location");
|
||||||
|
System.out.println(num + ":" + location);
|
||||||
|
})
|
||||||
|
.onFailure(handleFail("连接失败"));
|
||||||
|
try {
|
||||||
|
TimeUnit.MILLISECONDS.sleep(100);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return promise.future();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
new QkTool("https://pimapi.lenovomm.com/clouddiskapi/v1/shareRedirect?si=12298704&dk" +
|
||||||
|
"=19ab590770399d4438ea885446e27186cc668cdfa559f5fcc063a1ecf78008e5&pk" +
|
||||||
|
"=ef45aa4d25c1dcecb631b3394f51539d59cb35c6a40c3911df8ba431ba2a3244&pc=true&ot=ali&ob=sync-cloud-disk" +
|
||||||
|
"&ok=649593714557087744.dex&fn=classes" +
|
||||||
|
".dex&ds=8909208&dc=1&bi=asdddsad&ri=&ts=1701235051759&sn" +
|
||||||
|
"=13dc33749bd9cc108009fa505b3ecca9f358d70874352858475956ba4240e4c3", "")
|
||||||
|
.parse().onSuccess((res) -> {
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package cn.qaiu.lz.common.parser.impl;
|
package cn.qaiu.parser.impl;
|
||||||
|
|
||||||
import cn.qaiu.lz.common.parser.IPanTool;
|
import cn.qaiu.parser.IPanTool;
|
||||||
import cn.qaiu.lz.common.parser.PanBase;
|
import cn.qaiu.parser.PanBase;
|
||||||
import cn.qaiu.lz.common.util.CommonUtils;
|
import cn.qaiu.util.CommonUtils;
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
import io.vertx.core.json.JsonArray;
|
import io.vertx.core.json.JsonArray;
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
183
parser/src/main/java/cn/qaiu/parser/impl/WsTool.java
Normal file
183
parser/src/main/java/cn/qaiu/parser/impl/WsTool.java
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
package cn.qaiu.parser.impl;
|
||||||
|
|
||||||
|
import cn.qaiu.util.StringUtils;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
|
||||||
|
import cn.qaiu.parser.IPanTool;
|
||||||
|
import cn.qaiu.parser.PanBase;
|
||||||
|
import io.vertx.core.Future;
|
||||||
|
import io.vertx.core.MultiMap;
|
||||||
|
import io.vertx.core.json.DecodeException;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.ext.web.client.WebClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <a href="https://www.wenshushu.cn/">文叔叔</a>
|
||||||
|
*/
|
||||||
|
public class WsTool extends PanBase implements IPanTool {
|
||||||
|
|
||||||
|
public static final String SHARE_URL_PREFIX = "www.wenshushu.cn/f/";
|
||||||
|
public static final String SHARE_URL_PREFIX2 = "f.ws59.cn/f/";
|
||||||
|
public static final String SHARE_URL_API = "https://www.wenshushu.cn/ap/";
|
||||||
|
|
||||||
|
public WsTool(String key, String pwd) {
|
||||||
|
super(key, pwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Future<String> parse() {
|
||||||
|
|
||||||
|
WebClient httpClient = this.client;
|
||||||
|
|
||||||
|
// 补全链接
|
||||||
|
if (!this.key.startsWith("https://" + SHARE_URL_PREFIX) && !this.key.startsWith("https://" + SHARE_URL_PREFIX2)) {
|
||||||
|
if (this.key.startsWith(SHARE_URL_PREFIX) || this.key.startsWith(SHARE_URL_PREFIX2)) {
|
||||||
|
this.key = "https://" + this.key;
|
||||||
|
} else if (this.key.matches("^[A-Za-z0-9]+$")) {
|
||||||
|
this.key = "https://" + SHARE_URL_PREFIX + this.key;
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException("未知分享类型");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置基础HTTP头部
|
||||||
|
var userAgent2 = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, " +
|
||||||
|
"like " +
|
||||||
|
"Gecko) Chrome/111.0.0.0 Mobile Safari/537.36";
|
||||||
|
|
||||||
|
MultiMap headers = MultiMap.caseInsensitiveMultiMap();
|
||||||
|
headers.set("User-Agent", userAgent2);
|
||||||
|
headers.set("sec-ch-ua-platform", "Android");
|
||||||
|
headers.set("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
|
||||||
|
headers.set("sec-ch-ua-mobile", "sec-ch-ua-mobile");
|
||||||
|
|
||||||
|
// 获取匿名登录token
|
||||||
|
httpClient.postAbs(SHARE_URL_API + "login/anonymous").putHeaders(headers)
|
||||||
|
.sendJsonObject(JsonObject.of("dev_info", "{}"))
|
||||||
|
.onSuccess(res -> {
|
||||||
|
|
||||||
|
if (res.statusCode() == 200) {
|
||||||
|
try {
|
||||||
|
// 设置匿名登录token
|
||||||
|
String token = res.bodyAsJsonObject().getJsonObject("data").getString("token");
|
||||||
|
headers.set("X-Token", token);
|
||||||
|
|
||||||
|
// 获取文件夹信息
|
||||||
|
httpClient.postAbs(SHARE_URL_API + "task/mgrtask").putHeaders(headers)
|
||||||
|
.sendJsonObject(JsonObject.of(
|
||||||
|
"tid", StringUtils.StringCutNot(key, this.key.startsWith(SHARE_URL_PREFIX) ? SHARE_URL_PREFIX : SHARE_URL_PREFIX2),
|
||||||
|
"password", ""
|
||||||
|
)).onSuccess(res2 -> {
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// 调试输出文件夹信息
|
||||||
|
System.out.println("文件夹期限: " + filetime);
|
||||||
|
System.out.println("文件夹大小: " + filesize);
|
||||||
|
System.out.println("文件夹pid: " + filepid);
|
||||||
|
System.out.println("文件夹bid: " + filebid);
|
||||||
|
|
||||||
|
// 获取文件信息
|
||||||
|
httpClient.postAbs(SHARE_URL_API + "ufile/list").putHeaders(headers)
|
||||||
|
.sendJsonObject(JsonObject.of(
|
||||||
|
"start", 0,
|
||||||
|
"sort", JsonObject.of(
|
||||||
|
"name", "asc"
|
||||||
|
),
|
||||||
|
"bid", filebid,
|
||||||
|
"pid", filepid,
|
||||||
|
"type", 1,
|
||||||
|
"options", JsonObject.of(
|
||||||
|
"uploader", "true"
|
||||||
|
),
|
||||||
|
"size", 50
|
||||||
|
)).onSuccess(res3 -> {
|
||||||
|
|
||||||
|
if (res3.statusCode() == 200) {
|
||||||
|
try {
|
||||||
|
// 获取文件信息
|
||||||
|
String filename = res3.bodyAsJsonObject().getJsonObject("data")
|
||||||
|
.getJsonArray("fileList").getJsonObject(0).getString("fname"); // 文件名称
|
||||||
|
String filefid = res3.bodyAsJsonObject().getJsonObject("data")
|
||||||
|
.getJsonArray("fileList").getJsonObject(0).getString("fid"); // 文件fid
|
||||||
|
|
||||||
|
// 调试输出文件信息
|
||||||
|
System.out.println("文件名称: " + filename);
|
||||||
|
System.out.println("文件fid: " + filefid);
|
||||||
|
|
||||||
|
// 检查文件是否失效
|
||||||
|
httpClient.postAbs(SHARE_URL_API + "dl/sign").putHeaders(headers)
|
||||||
|
.sendJsonObject(JsonObject.of(
|
||||||
|
"consumeCode", 0,
|
||||||
|
"type", 1,
|
||||||
|
"ufileid", filefid
|
||||||
|
)).onSuccess(res4 -> {
|
||||||
|
|
||||||
|
if (res4.statusCode() == 200) {
|
||||||
|
try {
|
||||||
|
// 获取直链
|
||||||
|
String fileurl = res4.bodyAsJsonObject().getJsonObject("data").getString("url");
|
||||||
|
|
||||||
|
// 调试输出文件直链
|
||||||
|
System.out.println("文件直链: " + fileurl);
|
||||||
|
|
||||||
|
if (!fileurl.equals(""))
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
promise.complete(URLDecoder.decode(fileurl, "UTF-8"));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
promise.complete(fileurl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.fail("文件已失效");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (DecodeException | NullPointerException e) {
|
||||||
|
this.fail("获取文件信息失败,可能是分享链接的方式已更新,或者对方的文件已失效");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.fail("HTTP状态不正确,可能是分享链接的方式已更新");
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (DecodeException | NullPointerException e) {
|
||||||
|
this.fail("获取文件信息失败,可能是分享链接的方式已更新");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.fail("HTTP状态不正确,可能是分享链接的方式已更新");
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (DecodeException | NullPointerException e) {
|
||||||
|
this.fail("获取文件夹信息失败,可能是分享链接的方式已更新");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.fail("HTTP状态不正确,可能是分享链接的方式已更新");
|
||||||
|
}
|
||||||
|
|
||||||
|
}).onFailure(this.handleFail(this.key));
|
||||||
|
|
||||||
|
} catch (DecodeException | NullPointerException e) {
|
||||||
|
this.fail("token获取失败,可能是分享链接的方式已更新");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.fail("HTTP状态不正确,可能是分享链接的方式已更新");
|
||||||
|
}
|
||||||
|
|
||||||
|
}).onFailure(this.handleFail(this.key));
|
||||||
|
|
||||||
|
return promise.future();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package cn.qaiu.lz.common.parser.impl;
|
package cn.qaiu.parser.impl;
|
||||||
|
|
||||||
import cn.qaiu.lz.common.parser.IPanTool;
|
import cn.qaiu.parser.IPanTool;
|
||||||
import cn.qaiu.lz.common.parser.PanBase;
|
import cn.qaiu.parser.PanBase;
|
||||||
import cn.qaiu.lz.common.util.CommonUtils;
|
import cn.qaiu.util.CommonUtils;
|
||||||
import cn.qaiu.lz.common.util.JsExecUtils;
|
import cn.qaiu.util.JsExecUtils;
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
import io.vertx.ext.web.client.WebClient;
|
import io.vertx.ext.web.client.WebClient;
|
||||||
@@ -100,7 +100,7 @@ public class YeTool extends PanBase implements IPanTool {
|
|||||||
jsonObject.put("ShareKey", reqBodyJson.getString("ShareKey"));
|
jsonObject.put("ShareKey", reqBodyJson.getString("ShareKey"));
|
||||||
jsonObject.put("FileID", reqBodyJson.getInteger("FileId"));
|
jsonObject.put("FileID", reqBodyJson.getInteger("FileId"));
|
||||||
jsonObject.put("S3keyFlag", reqBodyJson.getString("S3KeyFlag"));
|
jsonObject.put("S3keyFlag", reqBodyJson.getString("S3KeyFlag"));
|
||||||
jsonObject.put("Size", reqBodyJson.getInteger("Size"));
|
jsonObject.put("Size", reqBodyJson.getLong("Size"));
|
||||||
jsonObject.put("Etag", reqBodyJson.getString("Etag"));
|
jsonObject.put("Etag", reqBodyJson.getString("Etag"));
|
||||||
|
|
||||||
// 调用JS文件获取签名
|
// 调用JS文件获取签名
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cn.qaiu.lz.common.util;
|
package cn.qaiu.util;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
@@ -34,7 +34,10 @@ public class AESUtils {
|
|||||||
|
|
||||||
public static final String CIPHER_AES2 = "YbQHZqK/PdQql2+7ATcPQHREAxt0Hn0Ob9v317QirZM=";
|
public static final String CIPHER_AES2 = "YbQHZqK/PdQql2+7ATcPQHREAxt0Hn0Ob9v317QirZM=";
|
||||||
|
|
||||||
|
public static final String CIPHER_AES2_IZ = "1uQFS3sNeHd/bCrmrQpflXREAxt0Hn0Ob9v317QirZM=";
|
||||||
|
|
||||||
public static final String CIPHER_AES0;
|
public static final String CIPHER_AES0;
|
||||||
|
public static final String CIPHER_AES0_IZ;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 秘钥长度
|
* 秘钥长度
|
||||||
@@ -59,6 +62,7 @@ public class AESUtils {
|
|||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
CIPHER_AES0 = decryptByBase64AES(CIPHER_AES2, CIPHER_AES);
|
CIPHER_AES0 = decryptByBase64AES(CIPHER_AES2, CIPHER_AES);
|
||||||
|
CIPHER_AES0_IZ = decryptByBase64AES(CIPHER_AES2_IZ, CIPHER_AES);
|
||||||
} catch (IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException | NoSuchAlgorithmException |
|
} catch (IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException | NoSuchAlgorithmException |
|
||||||
InvalidKeyException e) {
|
InvalidKeyException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@@ -154,6 +158,15 @@ public class AESUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String encrypt2HexIz(String source) {
|
||||||
|
try {
|
||||||
|
return encryptHexByAES(source, CIPHER_AES0_IZ);
|
||||||
|
} catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | IllegalBlockSizeException |
|
||||||
|
BadPaddingException e) {
|
||||||
|
throw new RuntimeException("加密失败: "+ e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AES解密
|
* AES解密
|
||||||
*
|
*
|
||||||
@@ -214,10 +227,14 @@ public class AESUtils {
|
|||||||
'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||||
'p', 'q', 'r', 's', 't', 'u', 'L', 'R', 'S', 'I',
|
'p', 'q', 'r', 's', 't', 'u', 'L', 'R', 'S', 'I',
|
||||||
'J', 'K'};
|
'J', 'K'};
|
||||||
|
private static final char[] arrayIz =
|
||||||
private static int decodeChar(char c) {
|
{'Y', 'y', '0', 'Z', 'z', 'N', 'n', 'M', 'I', '6', 'm', 'W', 'w', '1', 'X', 'x', 'L', 'l', 'K', '7', 'k',
|
||||||
for (int i = 0; i < array.length; i++) {
|
'i', 'U', 'u', '2', 'V', 'v', 'J', 'j', '8', 'G', 'g', 'F', 'S', 's', '3', 'T', 't', 'H', 'h',
|
||||||
if (c == array[i]) {
|
'f', 'E', 'e', 'D', 'Q', 'q', '4', 'R', 'r', '9', 'd', 'a', 'C', 'c', 'B', 'O', 'o', '5', 'P',
|
||||||
|
'p', 'b', 'A'};
|
||||||
|
private static int decodeChar(char c, char[] keys) {
|
||||||
|
for (int i = 0; i < keys.length; i++) {
|
||||||
|
if (c == keys[i]) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -226,21 +243,46 @@ public class AESUtils {
|
|||||||
|
|
||||||
// id解密
|
// id解密
|
||||||
public static int idEncrypt(String str) {
|
public static int idEncrypt(String str) {
|
||||||
|
return idEncrypt0(str, array, 2, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================蓝奏优享版Id解密========================================== //
|
||||||
|
public static int idEncryptIz(String str) {
|
||||||
|
// idEncrypt(e) {
|
||||||
|
// let t = 1
|
||||||
|
// , n = 0;
|
||||||
|
// if ("" != e && e.length > 4) {
|
||||||
|
// let r;
|
||||||
|
// e = e.substring(3, e.length - 1);
|
||||||
|
// for (let v = 0; v < e.length; v++)
|
||||||
|
// r = e.charAt(e.length - v - 1),
|
||||||
|
// n += this.decodeChar(r) * t,
|
||||||
|
// t *= 62
|
||||||
|
// }
|
||||||
|
// return n
|
||||||
|
// },
|
||||||
|
|
||||||
|
return idEncrypt0(str, arrayIz, 3, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int idEncrypt0(String str, char[] keys, int x1, int x2) {
|
||||||
// 倍数
|
// 倍数
|
||||||
int multiple = 1;
|
int multiple = 1;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
if (StringUtils.isNotEmpty(str) && str.length() > 4) {
|
if (StringUtils.isNotEmpty(str) && str.length() > 4) {
|
||||||
str = str.substring(2, str.length() - 2);
|
str = str.substring(x1, str.length() - x2);
|
||||||
char c;
|
char c;
|
||||||
for (int i = 0; i < str.length(); i++) {
|
for (int i = 0; i < str.length(); i++) {
|
||||||
c = str.charAt(str.length() - i - 1);
|
c = str.charAt(str.length() - i - 1);
|
||||||
result += decodeChar(c) * multiple;
|
result += decodeChar(c, keys) * multiple;
|
||||||
multiple = multiple * 62;
|
multiple = multiple * 62;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ========================== musetransfer加密相关 ===========================
|
// ========================== musetransfer加密相关 ===========================
|
||||||
|
|
||||||
//length用户要求产生字符串的长度
|
//length用户要求产生字符串的长度
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cn.qaiu.lz.common.util;
|
package cn.qaiu.util;
|
||||||
|
|
||||||
public class ArrayUtil {
|
public class ArrayUtil {
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cn.qaiu.lz.common.util;
|
package cn.qaiu.util;
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
@@ -7,6 +7,12 @@ import java.util.Map;
|
|||||||
|
|
||||||
public class CommonUtils {
|
public class CommonUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取分享key 比如: https://www.ilanzou.com/s/xxx -> xxx
|
||||||
|
* @param urlPrefix 不包含key的URL前缀
|
||||||
|
* @param url 完整URL
|
||||||
|
* @return 分享key
|
||||||
|
*/
|
||||||
public static String adaptShortPaths(String urlPrefix, String url) {
|
public static String adaptShortPaths(String urlPrefix, String url) {
|
||||||
if (url.endsWith(".html")) {
|
if (url.endsWith(".html")) {
|
||||||
url = url.substring(0, url.length() - 5);
|
url = url.substring(0, url.length() - 5);
|
||||||
152
parser/src/main/java/cn/qaiu/util/JsContent.java
Normal file
152
parser/src/main/java/cn/qaiu/util/JsContent.java
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
package cn.qaiu.util;
|
||||||
|
|
||||||
|
public interface JsContent {
|
||||||
|
String ye123 = """
|
||||||
|
/*
|
||||||
|
https://statics.123pan.com/share-static/dist/umi.fb72555e.js
|
||||||
|
eaefamemdead
|
||||||
|
eaefameidldy
|
||||||
|
_0x4f141a(1690439821|5790548|/b/api/share/download/info|web|3|1946841013) = 秘钥
|
||||||
|
|
||||||
|
_0x1e2592 1690439821 时间戳
|
||||||
|
_0x48562f 5790548 随机码
|
||||||
|
_0x1e37d5 /b/api/share/download/info
|
||||||
|
_0x4e2d74 web
|
||||||
|
_0x56f040 3
|
||||||
|
_0x43bdc6 1946841013 加密时间HASH戳
|
||||||
|
|
||||||
|
>>>>
|
||||||
|
_0x43bdc6=''['concat'](_0x1e2592, '-')['concat'](_0x48562f, '-')['concat'](_0x406c4e)
|
||||||
|
加密时间HASH戳 = 时间戳-随机码-秘钥
|
||||||
|
*/
|
||||||
|
|
||||||
|
function _0x1b5d95(_0x278d1a) {
|
||||||
|
var _0x839b57,
|
||||||
|
_0x4ed4dc = arguments['length'] > 0x2 && void 0x0 !== arguments[0x2] ? arguments[0x2] : 0x8;
|
||||||
|
if (0x0 === arguments['length'])
|
||||||
|
return null;
|
||||||
|
'object' === typeof _0x278d1a ? _0x839b57 = _0x278d1a : (0xa === ('' + _0x278d1a)['length'] && (_0x278d1a = 0x3e8 * parseInt(_0x278d1a)),
|
||||||
|
_0x839b57 = new Date(_0x278d1a));
|
||||||
|
var _0xc5c54a = _0x278d1a + 0xea60 * new Date(_0x278d1a)['getTimezoneOffset']()
|
||||||
|
, _0x3732dc = _0xc5c54a + 0x36ee80 * _0x4ed4dc;
|
||||||
|
return _0x839b57 = new Date(_0x3732dc),
|
||||||
|
{
|
||||||
|
'y': _0x839b57['getFullYear'](),
|
||||||
|
'm': _0x839b57['getMonth']() + 0x1 < 0xa ? '0' + (_0x839b57['getMonth']() + 0x1) : _0x839b57['getMonth']() + 0x1,
|
||||||
|
'd': _0x839b57['getDate']() < 0xa ? '0' + _0x839b57['getDate']() : _0x839b57['getDate'](),
|
||||||
|
'h': _0x839b57['getHours']() < 0xa ? '0' + _0x839b57['getHours']() : _0x839b57['getHours'](),
|
||||||
|
'f': _0x839b57['getMinutes']() < 0xa ? '0' + _0x839b57['getMinutes']() : _0x839b57['getMinutes']()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function _0x4f141a(_0x4075b1) {
|
||||||
|
|
||||||
|
for (var _0x4eddcb = arguments['length'] > 0x1 && void 0x0 !== arguments[0x1] ? arguments[0x1] : 0xa,
|
||||||
|
_0x2fc680 = function() {
|
||||||
|
for (var _0x515c63, _0x361314 = [], _0x4cbdba = 0x0; _0x4cbdba < 0x100; _0x4cbdba++) {
|
||||||
|
_0x515c63 = _0x4cbdba;
|
||||||
|
for (var _0x460960 = 0x0; _0x460960 < 0x8; _0x460960++)
|
||||||
|
_0x515c63 = 0x1 & _0x515c63 ? 0xedb88320 ^ _0x515c63 >>> 0x1 : _0x515c63 >>> 0x1;
|
||||||
|
_0x361314[_0x4cbdba] = _0x515c63;
|
||||||
|
}
|
||||||
|
return _0x361314;
|
||||||
|
},
|
||||||
|
_0x4aed86 = _0x2fc680(),
|
||||||
|
_0x5880f0 = _0x4075b1,
|
||||||
|
_0x492393 = -0x1, _0x25d82c = 0x0;
|
||||||
|
_0x25d82c < _0x5880f0['length'];
|
||||||
|
_0x25d82c++)
|
||||||
|
|
||||||
|
_0x492393 = _0x492393 >>> 0x8 ^ _0x4aed86[0xff & (_0x492393 ^ _0x5880f0.charCodeAt(_0x25d82c))];
|
||||||
|
return _0x492393 = (-0x1 ^ _0x492393) >>> 0x0,
|
||||||
|
_0x492393.toString(_0x4eddcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getSign(_0x1e37d5) {
|
||||||
|
var _0x4e2d74 = 'web';
|
||||||
|
var _0x56f040 = 3;
|
||||||
|
var _0x1e2592 = Math.round((new Date().getTime() + 0x3c * new Date().getTimezoneOffset() * 0x3e8 + 28800000) / 0x3e8).toString();
|
||||||
|
var key = 'a,d,e,f,g,h,l,m,y,i,j,n,o,p,k,q,r,s,t,u,b,c,v,w,s,z';
|
||||||
|
var _0x48562f = Math['round'](0x989680 * Math['random']());
|
||||||
|
|
||||||
|
var _0x2f7dfc;
|
||||||
|
var _0x35a889;
|
||||||
|
var _0x36f983;
|
||||||
|
var _0x3b043d;
|
||||||
|
var _0x5bc73b;
|
||||||
|
var _0x4b30b2;
|
||||||
|
var _0x32399e;
|
||||||
|
var _0x25d94e;
|
||||||
|
var _0x373490;
|
||||||
|
for (var _0x1c540f in (_0x2f7dfc = key.split(','),
|
||||||
|
_0x35a889 = _0x1b5d95(_0x1e2592),
|
||||||
|
_0x36f983 = _0x35a889['y'],
|
||||||
|
_0x3b043d = _0x35a889['m'],
|
||||||
|
_0x5bc73b = _0x35a889['d'],
|
||||||
|
_0x4b30b2 = _0x35a889['h'],
|
||||||
|
_0x32399e = _0x35a889['f'],
|
||||||
|
_0x25d94e = [_0x36f983, _0x3b043d, _0x5bc73b, _0x4b30b2, _0x32399e].join(''),
|
||||||
|
_0x373490 = [],
|
||||||
|
_0x25d94e))
|
||||||
|
_0x373490['push'](_0x2f7dfc[Number(_0x25d94e[_0x1c540f])]);
|
||||||
|
var _0x43bdc6;
|
||||||
|
var _0x406c4e;
|
||||||
|
return _0x43bdc6 = _0x4f141a(_0x373490['join']('')),
|
||||||
|
_0x406c4e = _0x4f141a(''['concat'](_0x1e2592, '|')['concat'](_0x48562f, '|')['concat'](_0x1e37d5, '|')['concat'](_0x4e2d74, '|')['concat'](_0x56f040, '|')['concat'](_0x43bdc6)),
|
||||||
|
[_0x43bdc6, ''['concat'](_0x1e2592, '-')['concat'](_0x48562f, '-')['concat'](_0x406c4e)];
|
||||||
|
}
|
||||||
|
|
||||||
|
""";
|
||||||
|
String lz = """
|
||||||
|
/**
|
||||||
|
* 蓝奏云解析器js签名获取工具
|
||||||
|
*/
|
||||||
|
|
||||||
|
var signObj;
|
||||||
|
|
||||||
|
|
||||||
|
var $, jQuery;
|
||||||
|
|
||||||
|
$ = jQuery = function () {
|
||||||
|
return new jQuery.fn.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery.fn = jQuery.prototype = {
|
||||||
|
init: function () {
|
||||||
|
return {
|
||||||
|
focus: function (a) {
|
||||||
|
|
||||||
|
},
|
||||||
|
keyup: function(a) {
|
||||||
|
|
||||||
|
},
|
||||||
|
ajax: function (obj) {
|
||||||
|
signObj = obj
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery.fn.init.prototype = jQuery.fn;
|
||||||
|
|
||||||
|
|
||||||
|
// 伪装jquery.ajax函数获取关键数据
|
||||||
|
$.ajax = function (obj) {
|
||||||
|
signObj = obj
|
||||||
|
}
|
||||||
|
|
||||||
|
var document = {
|
||||||
|
getElementById: function (v) {
|
||||||
|
return {
|
||||||
|
value: 'v'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cn.qaiu.lz.common.util;
|
package cn.qaiu.util;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.openjdk.nashorn.api.scripting.ScriptObjectMirror;
|
import org.openjdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||||
@@ -7,12 +7,6 @@ import javax.script.Invocable;
|
|||||||
import javax.script.ScriptEngine;
|
import javax.script.ScriptEngine;
|
||||||
import javax.script.ScriptEngineManager;
|
import javax.script.ScriptEngineManager;
|
||||||
import javax.script.ScriptException;
|
import javax.script.ScriptException;
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行Js脚本
|
* 执行Js脚本
|
||||||
@@ -21,28 +15,17 @@ import java.nio.file.Paths;
|
|||||||
* @date 2023/7/29 17:35
|
* @date 2023/7/29 17:35
|
||||||
*/
|
*/
|
||||||
public class JsExecUtils {
|
public class JsExecUtils {
|
||||||
private static final String JS_PATH = "js/ye123.js";
|
|
||||||
private static final String LZ_JS_PATH = "js/lz.js";
|
|
||||||
|
|
||||||
private static final String RES_PATH;
|
|
||||||
private static final Invocable inv;
|
private static final Invocable inv;
|
||||||
|
|
||||||
// 初始化脚本引擎
|
// 初始化脚本引擎
|
||||||
static {
|
static {
|
||||||
ScriptEngineManager engineManager = new ScriptEngineManager();
|
ScriptEngineManager engineManager = new ScriptEngineManager();
|
||||||
ScriptEngine engine = engineManager.getEngineByName("JavaScript"); // 得到脚本引擎
|
ScriptEngine engine = engineManager.getEngineByName("JavaScript"); // 得到脚本引擎
|
||||||
//获取文件所在的相对路径
|
|
||||||
URL resource = JsExecUtils.class.getResource("/");
|
try {
|
||||||
if (resource == null) {
|
engine.eval(JsContent.ye123);
|
||||||
throw new RuntimeException("js resource path is null");
|
|
||||||
}
|
|
||||||
RES_PATH = resource.getPath();
|
|
||||||
String reader = RES_PATH + JS_PATH;
|
|
||||||
try (FileReader fReader = new FileReader(reader)) {
|
|
||||||
engine.eval(fReader);
|
|
||||||
fReader.close();
|
|
||||||
inv = (Invocable) engine;
|
inv = (Invocable) engine;
|
||||||
} catch (IOException | ScriptException e) {
|
} catch (ScriptException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,23 +46,11 @@ public class JsExecUtils {
|
|||||||
NoSuchMethodException {
|
NoSuchMethodException {
|
||||||
ScriptEngineManager engineManager = new ScriptEngineManager();
|
ScriptEngineManager engineManager = new ScriptEngineManager();
|
||||||
ScriptEngine engine = engineManager.getEngineByName("JavaScript"); // 得到脚本引擎
|
ScriptEngine engine = engineManager.getEngineByName("JavaScript"); // 得到脚本引擎
|
||||||
try {
|
engine.eval(JsContent.lz + "\n" + jsText);
|
||||||
//获取文件所在的相对路径
|
Invocable inv = (Invocable) engine;
|
||||||
Path path;
|
//调用js中的函数
|
||||||
try {
|
if (StringUtils.isNotEmpty(funName)) {
|
||||||
path = Paths.get(RES_PATH + LZ_JS_PATH);
|
inv.invokeFunction(funName);
|
||||||
} catch (RuntimeException ioe) {
|
|
||||||
path = Paths.get(RES_PATH.substring(1) + LZ_JS_PATH);
|
|
||||||
}
|
|
||||||
String jsContent = Files.readString(path) + "\n" + jsText;
|
|
||||||
engine.eval(jsContent);
|
|
||||||
Invocable inv = (Invocable) engine;
|
|
||||||
//调用js中的函数
|
|
||||||
if (StringUtils.isNotEmpty(funName)) {
|
|
||||||
inv.invokeFunction(funName);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (ScriptObjectMirror) engine.get("signObj");
|
return (ScriptObjectMirror) engine.get("signObj");
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cn.qaiu.lz.common.util;
|
package cn.qaiu.util;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="https://qaiu.top">QAIU</a>
|
* @author <a href="https://qaiu.top">QAIU</a>
|
||||||
36
parser/src/main/java/cn/qaiu/util/StringUtils.java
Normal file
36
parser/src/main/java/cn/qaiu/util/StringUtils.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package cn.qaiu.util;
|
||||||
|
|
||||||
|
public class StringUtils {
|
||||||
|
|
||||||
|
// 非贪婪截断匹配
|
||||||
|
public static String StringCutNot(final String strtarget, final String strstart)
|
||||||
|
{
|
||||||
|
int startIdx = strtarget.indexOf(strstart);
|
||||||
|
|
||||||
|
if (startIdx != -1) {
|
||||||
|
startIdx += strstart.length();
|
||||||
|
return strtarget.substring(startIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 非贪婪截断匹配
|
||||||
|
public static String StringCutNot(final String strtarget, final String strstart, final String strend)
|
||||||
|
{
|
||||||
|
int startIdx = strtarget.indexOf(strstart);
|
||||||
|
int endIdx = -1;
|
||||||
|
|
||||||
|
if (startIdx != -1) {
|
||||||
|
startIdx += strstart.length();
|
||||||
|
endIdx = strtarget.indexOf(strend, startIdx);
|
||||||
|
|
||||||
|
if (endIdx != -1) {
|
||||||
|
return strtarget.substring(startIdx, endIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
61
parser/src/main/resources/logback.xml
Normal file
61
parser/src/main/resources/logback.xml
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
|
||||||
|
<!-- 日志自定义颜色 -->
|
||||||
|
<!-- https://logback.qos.ch/manual/layouts.html#coloring -->
|
||||||
|
|
||||||
|
<!--日志文件主目录:这里${user.home}为当前服务器用户主目录-->
|
||||||
|
<property name="LOG_HOME" value="logs"/>
|
||||||
|
<!--日志文件名称:这里spring.application.name表示工程名称-->
|
||||||
|
|
||||||
|
<property name="LOGBACK_DEFAULT" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/>
|
||||||
|
<property name="CUSTOMER_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %magenta([%t]) %highlight(%-5p) %yellow(${PID:-}) %cyan(%-40.40logger{39}) : %green(%m%n)"/>
|
||||||
|
<property name="CUSTOMER_PATTERN2" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) -> %magenta([%15.15thread]) %cyan(%-40.40logger{39}) : %msg%n"/>
|
||||||
|
|
||||||
|
<!--配置日志文件(File)-->
|
||||||
|
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<!--设置策略-->
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<!--日志文件路径:这里%d{yyyyMMdd}表示按天分类日志-->
|
||||||
|
<FileNamePattern>${LOG_HOME}/%d{yyyyMMdd}/run.log</FileNamePattern>
|
||||||
|
<!--日志保留天数-->
|
||||||
|
<MaxHistory>15</MaxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<!--设置格式-->
|
||||||
|
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||||
|
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
|
||||||
|
<!-- 或者使用默认配置 -->
|
||||||
|
<!--<pattern>${FILE_LOG_PATTERN}</pattern>-->
|
||||||
|
<charset>utf8</charset>
|
||||||
|
</encoder>
|
||||||
|
<!--日志文件最大的大小-->
|
||||||
|
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
|
||||||
|
<MaxFileSize>100MB</MaxFileSize>
|
||||||
|
</triggeringPolicy>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- 将文件输出设置成异步输出 -->
|
||||||
|
<appender name="ASYNC-FILE" class="ch.qos.logback.classic.AsyncAppender">
|
||||||
|
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
|
||||||
|
<discardingThreshold>0</discardingThreshold>
|
||||||
|
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
|
||||||
|
<queueSize>256</queueSize>
|
||||||
|
<!-- 添加附加的appender,最多只能添加一个 -->
|
||||||
|
<appender-ref ref="FILE"/>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
|
||||||
|
<pattern>${CUSTOMER_PATTERN2}</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
<logger name="io.netty" level="warn"/>
|
||||||
|
<logger name="io.vertx" level="info"/>
|
||||||
|
<logger name="com.zaxxer.hikari" level="info"/>
|
||||||
|
<root level="info">
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<!-- <appender-ref ref="FILE"/>-->
|
||||||
|
</root>
|
||||||
|
</configuration>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package cn.qaiu.web.test;
|
package qaiu.web.test;
|
||||||
|
|
||||||
import cn.qaiu.lz.common.util.AESUtils;
|
import cn.qaiu.util.AESUtils;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -50,6 +50,12 @@ public class TestAESUtil {
|
|||||||
Assert.assertEquals(146731, AESUtils.idEncrypt("7jy0zlv"));
|
Assert.assertEquals(146731, AESUtils.idEncrypt("7jy0zlv"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 蓝奏优享
|
||||||
|
@Test
|
||||||
|
public void testIzIdDecode() {
|
||||||
|
Assert.assertEquals(26216, AESUtils.idEncryptIz("lGFndCM"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test00() throws IllegalBlockSizeException, NoSuchPaddingException, BadPaddingException,
|
public void test00() throws IllegalBlockSizeException, NoSuchPaddingException, BadPaddingException,
|
||||||
NoSuchAlgorithmException, InvalidKeyException {
|
NoSuchAlgorithmException, InvalidKeyException {
|
||||||
24
parser/src/test/java/qaiu/web/test/TestRegex.java
Normal file
24
parser/src/test/java/qaiu/web/test/TestRegex.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package qaiu.web.test;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class TestRegex {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void regexYFC() {
|
||||||
|
String html = """
|
||||||
|
<input type="hidden" id="typed_id" value="file_559003251828">
|
||||||
|
<input type="hidden" id="share_link_token" value="9cbe4b73521ba4d65a8cd38a8c">
|
||||||
|
""";
|
||||||
|
|
||||||
|
Pattern compile = Pattern.compile("id=\"typed_id\"\\s+value=\"file_(\\d+)\"");
|
||||||
|
Matcher matcher = compile.matcher(html);
|
||||||
|
if (matcher.find()) {
|
||||||
|
System.out.println(matcher.group(0));
|
||||||
|
System.out.println(matcher.group(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
package cn.qaiu.web.test;
|
package qaiu.web.test;
|
||||||
|
|
||||||
import io.vertx.core.MultiMap;
|
import io.vertx.core.MultiMap;
|
||||||
import io.vertx.core.Vertx;
|
import io.vertx.core.Vertx;
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
import io.vertx.ext.web.client.WebClient;
|
import io.vertx.ext.web.client.WebClient;
|
||||||
import org.apache.commons.lang3.RegExUtils;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cn.qaiu.web.test;
|
package qaiu.web.test;
|
||||||
|
|
||||||
import io.vertx.core.MultiMap;
|
import io.vertx.core.MultiMap;
|
||||||
import io.vertx.core.Vertx;
|
import io.vertx.core.Vertx;
|
||||||
22
pom.xml
22
pom.xml
@@ -7,20 +7,31 @@
|
|||||||
<groupId>cn.qaiu</groupId>
|
<groupId>cn.qaiu</groupId>
|
||||||
<artifactId>netdisk-fast-download</artifactId>
|
<artifactId>netdisk-fast-download</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<version>0.1.6</version>
|
<version>0.1.7</version>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>core</module>
|
<module>core</module>
|
||||||
<module>web-service</module>
|
<module>web-service</module>
|
||||||
<module>core-database</module>
|
<module>core-database</module>
|
||||||
|
<module>parser</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
<java.version>17</java.version>
|
||||||
<maven.compiler.source>17</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>17</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
|
||||||
<packageDirectory>${project.basedir}/web-service/target/package</packageDirectory>
|
<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.12</lombok.version>
|
||||||
|
<slf4j.version>2.0.5</slf4j.version>
|
||||||
|
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||||
|
<jackson.version>2.14.2</jackson.version>
|
||||||
|
<logback.version>1.4.12</logback.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@@ -105,14 +116,7 @@
|
|||||||
<!--<failOnError>false</failOnError>-->
|
<!--<failOnError>false</failOnError>-->
|
||||||
<!--当配置true时,只清理filesets里的文件,构建目录中得文件不被清理.默认是flase.-->
|
<!--当配置true时,只清理filesets里的文件,构建目录中得文件不被清理.默认是flase.-->
|
||||||
<excludeDefaultDirectories>false</excludeDefaultDirectories>
|
<excludeDefaultDirectories>false</excludeDefaultDirectories>
|
||||||
<filesets>
|
|
||||||
<fileset>
|
|
||||||
<!--要清理的目录位置-->
|
|
||||||
<directory>${project.basedir}/logs</directory>
|
|
||||||
<!--是否跟随符号链接 (symbolic links)-->
|
|
||||||
<followSymlinks>false</followSymlinks>
|
|
||||||
</fileset>
|
|
||||||
</filesets>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
|||||||
152
web-front/package-lock.json
generated
152
web-front/package-lock.json
generated
@@ -8,7 +8,7 @@
|
|||||||
"name": "nfd-web",
|
"name": "nfd-web",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.2.2",
|
"axios": "^1.6.0",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"element-ui": "^2.15.12",
|
"element-ui": "^2.15.12",
|
||||||
"vue": "^2.6.14",
|
"vue": "^2.6.14",
|
||||||
@@ -56,12 +56,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
"version": "7.18.6",
|
"version": "7.22.13",
|
||||||
"resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
|
||||||
"integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
|
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/highlight": "^7.18.6"
|
"@babel/highlight": "^7.22.13",
|
||||||
|
"chalk": "^2.4.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -121,13 +122,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/generator": {
|
"node_modules/@babel/generator": {
|
||||||
"version": "7.20.7",
|
"version": "7.23.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.20.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
|
||||||
"integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==",
|
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.20.7",
|
"@babel/types": "^7.23.0",
|
||||||
"@jridgewell/gen-mapping": "^0.3.2",
|
"@jridgewell/gen-mapping": "^0.3.2",
|
||||||
|
"@jridgewell/trace-mapping": "^0.3.17",
|
||||||
"jsesc": "^2.5.1"
|
"jsesc": "^2.5.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -248,9 +250,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-environment-visitor": {
|
"node_modules/@babel/helper-environment-visitor": {
|
||||||
"version": "7.18.9",
|
"version": "7.22.20",
|
||||||
"resolved": "https://registry.npmmirror.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
|
||||||
"integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
|
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -269,25 +271,25 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-function-name": {
|
"node_modules/@babel/helper-function-name": {
|
||||||
"version": "7.19.0",
|
"version": "7.23.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
|
||||||
"integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
|
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/template": "^7.18.10",
|
"@babel/template": "^7.22.15",
|
||||||
"@babel/types": "^7.19.0"
|
"@babel/types": "^7.23.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-hoist-variables": {
|
"node_modules/@babel/helper-hoist-variables": {
|
||||||
"version": "7.18.6",
|
"version": "7.22.5",
|
||||||
"resolved": "https://registry.npmmirror.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
|
||||||
"integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
|
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.18.6"
|
"@babel/types": "^7.22.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -417,30 +419,30 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-split-export-declaration": {
|
"node_modules/@babel/helper-split-export-declaration": {
|
||||||
"version": "7.18.6",
|
"version": "7.22.6",
|
||||||
"resolved": "https://registry.npmmirror.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
|
||||||
"integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
|
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.18.6"
|
"@babel/types": "^7.22.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-string-parser": {
|
"node_modules/@babel/helper-string-parser": {
|
||||||
"version": "7.19.4",
|
"version": "7.22.5",
|
||||||
"resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
|
||||||
"integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
|
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-validator-identifier": {
|
"node_modules/@babel/helper-validator-identifier": {
|
||||||
"version": "7.19.1",
|
"version": "7.22.20",
|
||||||
"resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||||
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
|
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -485,13 +487,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/highlight": {
|
"node_modules/@babel/highlight": {
|
||||||
"version": "7.18.6",
|
"version": "7.22.20",
|
||||||
"resolved": "https://registry.npmmirror.com/@babel/highlight/-/highlight-7.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
|
||||||
"integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
|
"integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-validator-identifier": "^7.18.6",
|
"@babel/helper-validator-identifier": "^7.22.20",
|
||||||
"chalk": "^2.0.0",
|
"chalk": "^2.4.2",
|
||||||
"js-tokens": "^4.0.0"
|
"js-tokens": "^4.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -499,9 +501,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/parser": {
|
"node_modules/@babel/parser": {
|
||||||
"version": "7.20.7",
|
"version": "7.23.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.20.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
|
||||||
"integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==",
|
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"parser": "bin/babel-parser.js"
|
"parser": "bin/babel-parser.js"
|
||||||
},
|
},
|
||||||
@@ -1676,33 +1678,33 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/template": {
|
"node_modules/@babel/template": {
|
||||||
"version": "7.20.7",
|
"version": "7.22.15",
|
||||||
"resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.20.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
|
||||||
"integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
|
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.18.6",
|
"@babel/code-frame": "^7.22.13",
|
||||||
"@babel/parser": "^7.20.7",
|
"@babel/parser": "^7.22.15",
|
||||||
"@babel/types": "^7.20.7"
|
"@babel/types": "^7.22.15"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/traverse": {
|
"node_modules/@babel/traverse": {
|
||||||
"version": "7.20.12",
|
"version": "7.23.2",
|
||||||
"resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.20.12.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
|
||||||
"integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==",
|
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.18.6",
|
"@babel/code-frame": "^7.22.13",
|
||||||
"@babel/generator": "^7.20.7",
|
"@babel/generator": "^7.23.0",
|
||||||
"@babel/helper-environment-visitor": "^7.18.9",
|
"@babel/helper-environment-visitor": "^7.22.20",
|
||||||
"@babel/helper-function-name": "^7.19.0",
|
"@babel/helper-function-name": "^7.23.0",
|
||||||
"@babel/helper-hoist-variables": "^7.18.6",
|
"@babel/helper-hoist-variables": "^7.22.5",
|
||||||
"@babel/helper-split-export-declaration": "^7.18.6",
|
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||||
"@babel/parser": "^7.20.7",
|
"@babel/parser": "^7.23.0",
|
||||||
"@babel/types": "^7.20.7",
|
"@babel/types": "^7.23.0",
|
||||||
"debug": "^4.1.0",
|
"debug": "^4.1.0",
|
||||||
"globals": "^11.1.0"
|
"globals": "^11.1.0"
|
||||||
},
|
},
|
||||||
@@ -1711,13 +1713,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/types": {
|
"node_modules/@babel/types": {
|
||||||
"version": "7.20.7",
|
"version": "7.23.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.20.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
|
||||||
"integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==",
|
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-string-parser": "^7.19.4",
|
"@babel/helper-string-parser": "^7.22.5",
|
||||||
"@babel/helper-validator-identifier": "^7.19.1",
|
"@babel/helper-validator-identifier": "^7.22.20",
|
||||||
"to-fast-properties": "^2.0.0"
|
"to-fast-properties": "^2.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -3562,9 +3564,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
"node_modules/axios": {
|
||||||
"version": "1.2.2",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz",
|
||||||
"integrity": "sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==",
|
"integrity": "sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"follow-redirects": "^1.15.0",
|
"follow-redirects": "^1.15.0",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
@@ -7238,9 +7240,15 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.15.2",
|
"version": "1.15.6",
|
||||||
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
|
||||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
},
|
},
|
||||||
@@ -13344,9 +13352,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/webpack-dev-middleware": {
|
"node_modules/webpack-dev-middleware": {
|
||||||
"version": "5.3.3",
|
"version": "5.3.4",
|
||||||
"resolved": "https://registry.npmmirror.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz",
|
||||||
"integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==",
|
"integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"colorette": "^2.0.10",
|
"colorette": "^2.0.10",
|
||||||
@@ -13358,6 +13366,10 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.13.0"
|
"node": ">= 12.13.0"
|
||||||
},
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/webpack"
|
||||||
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"webpack": "^4.0.0 || ^5.0.0"
|
"webpack": "^4.0.0 || ^5.0.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.2.2",
|
"axios": "^1.6.0",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"element-ui": "^2.15.12",
|
"element-ui": "^2.15.12",
|
||||||
"vue": "^2.6.14",
|
"vue": "^2.6.14",
|
||||||
|
|||||||
@@ -10,10 +10,16 @@
|
|||||||
<h3 style="text-align: center;">NFD网盘直链解析(API演示)</h3>
|
<h3 style="text-align: center;">NFD网盘直链解析(API演示)</h3>
|
||||||
<div class="typo">
|
<div class="typo">
|
||||||
<p><strong>项目GitHub </strong><a href="https://github.com/qaiu/netdisk-fast-download" target="_blank"
|
<p><strong>项目GitHub </strong><a href="https://github.com/qaiu/netdisk-fast-download" target="_blank"
|
||||||
rel="nofollow"><u>netdisk-fast-download</u></a></p>
|
rel="nofollow"><u>netdisk-fast-download</u></a></p>
|
||||||
<p><strong>当前页面修改自开源项目</strong><a href="https://github.com/HurryBy/CloudDiskAnalysis" target="_blank"
|
<p><strong>当前页面修改自开源项目</strong><a href="https://github.com/HurryBy/CloudDiskAnalysis"
|
||||||
rel="nofollow"><u>CloudDiskAnalysis</u></a></p>
|
target="_blank"
|
||||||
|
rel="nofollow"><u>CloudDiskAnalysis</u></a></p>
|
||||||
<p><strong>目前支持 </strong>已支持蓝奏云/奶牛快传/移动云云空间/UC网盘(暂时失效)/小飞机盘/亿方云/123云盘</p>
|
<p><strong>目前支持 </strong>已支持蓝奏云/奶牛快传/移动云云空间/UC网盘(暂时失效)/小飞机盘/亿方云/123云盘</p>
|
||||||
|
<p>
|
||||||
|
<el-button><strong @click="getInfo">刷新API调用统计</strong></el-button>
|
||||||
|
</p>
|
||||||
|
<p>节点1: 成功:{{ node1Info.success }},失败:{{ node1Info.fail }},总数:{{ node1Info.total }}</p>
|
||||||
|
<p>节点2: 成功:{{ node2Info.success }},失败:{{ node2Info.fail }},总数:{{ node2Info.total }}</p>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="main" v-loading="isLoading">
|
<div class="main" v-loading="isLoading">
|
||||||
@@ -24,10 +30,11 @@
|
|||||||
</el-input>
|
</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"></el-input>
|
||||||
<el-input v-show="respData.data" placeholder="解析地址" :value="getLink2" id="url" lass="input-with-select">
|
<el-input v-show="respData.data" placeholder="解析地址" :value="getLink2" id="url" lass="input-with-select">
|
||||||
<el-button slot="append" v-clipboard:copy="getLink2"
|
<el-button slot="append" v-clipboard:copy="getLink2"
|
||||||
v-clipboard:success="onCopy"
|
v-clipboard:success="onCopy"
|
||||||
v-clipboard:error="onError">点我复制</el-button>
|
v-clipboard:error="onError">点我复制
|
||||||
</el-input>
|
</el-button>
|
||||||
|
</el-input>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="respData.code" style="margin-top: 10px">
|
<div v-show="respData.code" style="margin-top: 10px">
|
||||||
<strong>解析结果: </strong>
|
<strong>解析结果: </strong>
|
||||||
@@ -113,7 +120,9 @@ export default {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
getLink: '',
|
getLink: '',
|
||||||
getLink2: ''
|
getLink2: '',
|
||||||
|
node1Info: {},
|
||||||
|
node2Info: {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -151,12 +160,30 @@ export default {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onCopy(){
|
onCopy() {
|
||||||
this.$message.success('复制成功')
|
this.$message.success('复制成功')
|
||||||
},
|
},
|
||||||
onError(){
|
onError() {
|
||||||
this.$message.error('复制失败')
|
this.$message.error('复制失败')
|
||||||
|
},
|
||||||
|
getInfo() {
|
||||||
|
// 初始化统计信息
|
||||||
|
axios.get('/n1/statisticsInfo').then(
|
||||||
|
response => {
|
||||||
|
if (response.data.success) {
|
||||||
|
this.node1Info = response.data.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
axios.get('/n2/statisticsInfo').then(
|
||||||
|
response => {
|
||||||
|
if (response.data.success) {
|
||||||
|
this.node2Info = response.data.data
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -5,19 +5,17 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>netdisk-fast-download</artifactId>
|
<artifactId>netdisk-fast-download</artifactId>
|
||||||
<groupId>cn.qaiu</groupId>
|
<groupId>cn.qaiu</groupId>
|
||||||
<version>0.1.6</version>
|
<version>0.1.7</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<version>0.1.6</version>
|
<version>0.1.7</version>
|
||||||
<artifactId>web-service</artifactId>
|
<artifactId>web-service</artifactId>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<packageDirectory>${project.basedir}/target/package</packageDirectory>
|
<packageDirectory>${project.basedir}/target/package</packageDirectory>
|
||||||
<java.version>17</java.version>
|
<java.version>17</java.version>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<slf4j.version>2.0.5</slf4j.version>
|
<finalName>netdisk-fast-download</finalName>
|
||||||
<vertx-jooq.version>6.1.0</vertx-jooq.version>
|
|
||||||
<finalName>netdisk-fast-download-${project.version}</finalName>
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -36,37 +34,35 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ch.qos.logback</groupId>
|
<groupId>ch.qos.logback</groupId>
|
||||||
<artifactId>logback-classic</artifactId>
|
<artifactId>logback-classic</artifactId>
|
||||||
<version>1.4.6</version>
|
<version>${logback.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.fusesource.jansi/jansi -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.fusesource.jansi</groupId>
|
||||||
|
<artifactId>jansi</artifactId>
|
||||||
|
<version>1.17.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
<version>${slf4j.version}</version>
|
<version>${slf4j.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.qaiu</groupId>
|
||||||
|
<artifactId>core-database</artifactId>
|
||||||
|
<version>0.1.7</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.qaiu</groupId>
|
||||||
|
<artifactId>parser</artifactId>
|
||||||
|
<version>0.1.7</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>4.13.2</version>
|
<version>4.13.2</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>io.vertx</groupId>
|
|
||||||
<artifactId>vertx-web-client</artifactId>
|
|
||||||
<version>4.4.1</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.qaiu</groupId>
|
|
||||||
<artifactId>core-database</artifactId>
|
|
||||||
<version>0.1.6</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- https://mvnrepository.com/artifact/org.openjdk.nashorn/nashorn-core -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.openjdk.nashorn</groupId>
|
|
||||||
<artifactId>nashorn-core</artifactId>
|
|
||||||
<version>15.4</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@@ -105,6 +101,8 @@
|
|||||||
<exclude>*.**</exclude>
|
<exclude>*.**</exclude>
|
||||||
<exclude>*/*.xml</exclude>
|
<exclude>*/*.xml</exclude>
|
||||||
<exclude>conf/**</exclude>
|
<exclude>conf/**</exclude>
|
||||||
|
<exclude>js/**</exclude>
|
||||||
|
<exclude>http-tools/**</exclude>
|
||||||
</excludes>
|
</excludes>
|
||||||
<archive>
|
<archive>
|
||||||
<manifest>
|
<manifest>
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package cn.qaiu.lz;
|
package cn.qaiu.lz;
|
||||||
|
|
||||||
|
import cn.qaiu.WebClientVertxInit;
|
||||||
import cn.qaiu.db.pool.JDBCPoolInit;
|
import cn.qaiu.db.pool.JDBCPoolInit;
|
||||||
import cn.qaiu.vx.core.Deploy;
|
import cn.qaiu.vx.core.Deploy;
|
||||||
import cn.qaiu.vx.core.util.ConfigConstant;
|
import cn.qaiu.vx.core.util.ConfigConstant;
|
||||||
|
import cn.qaiu.vx.core.util.VertxHolder;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.core.json.jackson.DatabindCodec;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,6 +28,8 @@ public class AppMain {
|
|||||||
* @param jsonObject 配置
|
* @param jsonObject 配置
|
||||||
*/
|
*/
|
||||||
private static void exec(JsonObject jsonObject) {
|
private static void exec(JsonObject jsonObject) {
|
||||||
|
WebClientVertxInit.init(VertxHolder.getVertxInstance());
|
||||||
|
DatabindCodec.mapper().registerModule(new JavaTimeModule());
|
||||||
if (jsonObject.getJsonObject(ConfigConstant.SERVER).getBoolean("enableDatabase")) {
|
if (jsonObject.getJsonObject(ConfigConstant.SERVER).getBoolean("enableDatabase")) {
|
||||||
JDBCPoolInit.builder().config(jsonObject.getJsonObject("dataSource")).build().initPool();
|
JDBCPoolInit.builder().config(jsonObject.getJsonObject("dataSource")).build().initPool();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,14 +16,12 @@ import static cn.qaiu.vx.core.util.ConfigConstant.IGNORES_REG;
|
|||||||
@HandleSortFilter(1)
|
@HandleSortFilter(1)
|
||||||
public class DefaultInterceptor implements BeforeInterceptor {
|
public class DefaultInterceptor implements BeforeInterceptor {
|
||||||
|
|
||||||
|
|
||||||
protected final JsonArray ignores = SharedDataUtil.getJsonArrayForCustomConfig(IGNORES_REG);
|
protected final JsonArray ignores = SharedDataUtil.getJsonArrayForCustomConfig(IGNORES_REG);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(RoutingContext ctx) {
|
public void handle(RoutingContext ctx) {
|
||||||
System.out.println("进入前置拦截器->" + ctx.request().path());
|
System.out.println("进入前置拦截器1->" + ctx.request().path());
|
||||||
|
doNext(ctx);
|
||||||
ctx.next();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,68 @@
|
|||||||
package cn.qaiu.lz.common.interceptorImpl;
|
package cn.qaiu.lz.common.interceptorImpl;
|
||||||
|
|
||||||
|
import cn.qaiu.db.pool.JDBCPoolInit;
|
||||||
|
import cn.qaiu.lz.common.model.ParserLogInfo;
|
||||||
import cn.qaiu.vx.core.annotaions.HandleSortFilter;
|
import cn.qaiu.vx.core.annotaions.HandleSortFilter;
|
||||||
import cn.qaiu.vx.core.interceptor.AfterInterceptor;
|
import cn.qaiu.vx.core.interceptor.AfterInterceptor;
|
||||||
|
import cn.qaiu.vx.core.model.JsonResult;
|
||||||
|
import cn.qaiu.vx.core.util.CommonUtil;
|
||||||
import cn.qaiu.vx.core.util.SharedDataUtil;
|
import cn.qaiu.vx.core.util.SharedDataUtil;
|
||||||
import io.vertx.core.http.HttpServerRequest;
|
|
||||||
import io.vertx.core.json.JsonArray;
|
import io.vertx.core.json.JsonArray;
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.ext.web.RoutingContext;
|
||||||
|
import io.vertx.jdbcclient.JDBCPool;
|
||||||
|
import io.vertx.sqlclient.templates.SqlTemplate;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import static cn.qaiu.vx.core.util.ConfigConstant.IGNORES_REG;
|
import static cn.qaiu.vx.core.util.ConfigConstant.IGNORES_REG;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* 记录解析日志
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@HandleSortFilter(99)
|
@HandleSortFilter(99)
|
||||||
public class LogStatistics implements AfterInterceptor {
|
public class LogStatistics implements AfterInterceptor {
|
||||||
|
|
||||||
protected final JsonArray ignores = SharedDataUtil.getJsonArrayForCustomConfig(IGNORES_REG);
|
JDBCPool client = JDBCPoolInit.instance().getPool();
|
||||||
|
private final JsonArray ignores = SharedDataUtil.getJsonArrayForCustomConfig(IGNORES_REG);
|
||||||
@Override
|
@Override
|
||||||
public void handle(HttpServerRequest request, JsonObject responseData) {
|
public void handle(RoutingContext ctx, JsonObject responseData) {
|
||||||
System.out.println("后置拦截-->" + responseData + " path:" + request.path());
|
|
||||||
|
// 判断是否忽略
|
||||||
|
if (CommonUtil.matchRegList(ignores.getList(), ctx.request().path())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParserLogInfo parserLogInfo = new ParserLogInfo();
|
||||||
|
parserLogInfo.setPath(ctx.request().uri());
|
||||||
|
if (responseData == null) {
|
||||||
|
String location = ctx.response().headers().get("location");
|
||||||
|
if (location != null) {
|
||||||
|
parserLogInfo.setCode(200);
|
||||||
|
parserLogInfo.setData(location);
|
||||||
|
} else {
|
||||||
|
log.error("location不存在且responseData为空, path={}", ctx.request().path());
|
||||||
|
}
|
||||||
|
insert(parserLogInfo);
|
||||||
|
|
||||||
|
} else if (responseData.containsKey("code")) {
|
||||||
|
JsonResult<?> result = JsonResult.toJsonResult(responseData);
|
||||||
|
parserLogInfo.setCode(result.getCode());
|
||||||
|
parserLogInfo.setData(result.getCode() == 500 ? result.getMsg() : result.getData().toString());
|
||||||
|
insert(parserLogInfo);
|
||||||
|
} else {
|
||||||
|
log.error("未知json日志: {}, path: {}", responseData.encode(), ctx.request().path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(ParserLogInfo info) {
|
||||||
|
SqlTemplate
|
||||||
|
.forUpdate(client, "INSERT INTO t_parser_log_info VALUES (#{id},#{logTime},#{path},#{code},#{data})")
|
||||||
|
.mapFrom(ParserLogInfo.class)
|
||||||
|
.execute(info)
|
||||||
|
.onSuccess(res -> {
|
||||||
|
log.info("inserted log: id={}, path={}, code={}", info.getId(), info.getPath(), info.getCode());
|
||||||
|
}).onFailure(Throwable::printStackTrace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
package cn.qaiu.lz.common.model;
|
|
||||||
|
|
||||||
public class ParserInfo {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package cn.qaiu.lz.common.model;
|
||||||
|
|
||||||
|
import cn.qaiu.db.ddl.Length;
|
||||||
|
import cn.qaiu.db.ddl.Table;
|
||||||
|
import cn.qaiu.lz.common.util.SnowflakeIdWorker;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Table("t_parser_log_info")
|
||||||
|
public class ParserLogInfo {
|
||||||
|
String id = SnowflakeIdWorker.getStringId();
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS", timezone = "GMT+8")
|
||||||
|
Date logTime = new Date();
|
||||||
|
String path;
|
||||||
|
Integer code;
|
||||||
|
|
||||||
|
@Length(varcharSize = 4096)
|
||||||
|
String data;
|
||||||
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package cn.qaiu.lz.common.parser.impl;
|
|
||||||
|
|
||||||
import cn.qaiu.lz.common.parser.IPanTool;
|
|
||||||
import cn.qaiu.lz.common.parser.PanBase;
|
|
||||||
import io.vertx.core.Future;
|
|
||||||
import io.vertx.core.Promise;
|
|
||||||
|
|
||||||
public class QkTool extends PanBase implements IPanTool {
|
|
||||||
|
|
||||||
public QkTool(String key, String pwd) {
|
|
||||||
super(key, pwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Future<String> parse() {
|
|
||||||
Promise<String> promise = Promise.promise();
|
|
||||||
|
|
||||||
promise.complete("https://lz.qaiu.top");
|
|
||||||
return promise.future();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -96,7 +96,7 @@ public class SnowflakeIdWorker {
|
|||||||
*
|
*
|
||||||
* @return SnowflakeId
|
* @return SnowflakeId
|
||||||
*/
|
*/
|
||||||
public synchronized long nextId() {
|
public synchronized Long nextId() {
|
||||||
long timestamp = timeGen();
|
long timestamp = timeGen();
|
||||||
|
|
||||||
//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
|
//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
|
||||||
@@ -214,6 +214,14 @@ public class SnowflakeIdWorker {
|
|||||||
return snowflakeIdWorker;
|
return snowflakeIdWorker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
synchronized public static Long getLongId() {
|
||||||
|
return snowflakeIdWorker.nextId();
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized public static String getStringId() {
|
||||||
|
return snowflakeIdWorker.nextId().toString();
|
||||||
|
}
|
||||||
|
|
||||||
synchronized public static SnowflakeIdWorker idWorkerCluster(long workerId, long datacenterId) {
|
synchronized public static SnowflakeIdWorker idWorkerCluster(long workerId, long datacenterId) {
|
||||||
if (snowflakeIdWorkerCluster == null) {
|
if (snowflakeIdWorkerCluster == null) {
|
||||||
snowflakeIdWorkerCluster = new SnowflakeIdWorker(workerId, datacenterId);
|
snowflakeIdWorkerCluster = new SnowflakeIdWorker(workerId, datacenterId);
|
||||||
|
|||||||
32
web-service/src/main/java/cn/qaiu/lz/web/http/ParserApi.java
Normal file
32
web-service/src/main/java/cn/qaiu/lz/web/http/ParserApi.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
package cn.qaiu.lz.web.http;
|
package cn.qaiu.lz.web.http;
|
||||||
|
|
||||||
import cn.qaiu.lz.common.parser.IPanTool;
|
import cn.qaiu.parser.IPanTool;
|
||||||
import cn.qaiu.lz.common.parser.impl.EcTool;
|
import cn.qaiu.parser.impl.EcTool;
|
||||||
import cn.qaiu.lz.web.model.SysUser;
|
import cn.qaiu.parser.impl.QQTool;
|
||||||
import cn.qaiu.lz.web.service.UserService;
|
|
||||||
import cn.qaiu.vx.core.annotaions.RouteHandler;
|
import cn.qaiu.vx.core.annotaions.RouteHandler;
|
||||||
import cn.qaiu.vx.core.annotaions.RouteMapping;
|
import cn.qaiu.vx.core.annotaions.RouteMapping;
|
||||||
import cn.qaiu.vx.core.enums.RouteMethod;
|
import cn.qaiu.vx.core.enums.RouteMethod;
|
||||||
import cn.qaiu.vx.core.util.AsyncServiceUtil;
|
|
||||||
import cn.qaiu.vx.core.util.ResponseUtil;
|
import cn.qaiu.vx.core.util.ResponseUtil;
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
import io.vertx.core.Promise;
|
import io.vertx.core.Promise;
|
||||||
@@ -15,8 +13,6 @@ import io.vertx.core.http.HttpServerRequest;
|
|||||||
import io.vertx.core.http.HttpServerResponse;
|
import io.vertx.core.http.HttpServerResponse;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务API
|
* 服务API
|
||||||
* <br>Create date 2021/4/28 9:15
|
* <br>Create date 2021/4/28 9:15
|
||||||
@@ -27,14 +23,6 @@ import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE;
|
|||||||
@RouteHandler("/")
|
@RouteHandler("/")
|
||||||
public class ServerApi {
|
public class ServerApi {
|
||||||
|
|
||||||
private final UserService userService = AsyncServiceUtil.getAsyncServiceInstance(UserService.class);
|
|
||||||
|
|
||||||
@RouteMapping(value = "/login", method = RouteMethod.POST)
|
|
||||||
public Future<String> login(SysUser user) {
|
|
||||||
log.info("<------- login: {}", user.getUsername());
|
|
||||||
return userService.login(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
@RouteMapping(value = "/parser", method = RouteMethod.GET, order = 4)
|
@RouteMapping(value = "/parser", method = RouteMethod.GET, order = 4)
|
||||||
public Future<Void> parse(HttpServerResponse response, HttpServerRequest request, String url, String pwd) {
|
public Future<Void> parse(HttpServerResponse response, HttpServerRequest request, String url, String pwd) {
|
||||||
|
|
||||||
@@ -43,13 +31,15 @@ public class ServerApi {
|
|||||||
// 默认读取Url参数会被截断手动获取一下其他参数
|
// 默认读取Url参数会被截断手动获取一下其他参数
|
||||||
url = EcTool.SHARE_URL_PREFIX + request.getParam("data");
|
url = EcTool.SHARE_URL_PREFIX + request.getParam("data");
|
||||||
}
|
}
|
||||||
try {
|
if (url.contains(QQTool.SHARE_URL_PREFIX)) {
|
||||||
IPanTool.shareURLPrefixMatching(url, pwd).parse().onSuccess(resUrl -> {
|
// 默认读取Url参数会被截断手动获取一下其他参数
|
||||||
ResponseUtil.redirect(response, resUrl, promise);
|
url = url + "&key=" + request.getParam("key") +
|
||||||
}).onFailure(t -> promise.fail(t.fillInStackTrace()));
|
"&code=" + request.getParam("code") + "&k=" + request.getParam("k") +
|
||||||
} catch (Exception e) {
|
"&fweb=" + request.getParam("fweb") + "&cl=" + request.getParam("cl");
|
||||||
promise.fail(e);
|
|
||||||
}
|
}
|
||||||
|
IPanTool.shareURLPrefixMatching(url, pwd).parse()
|
||||||
|
.onSuccess(resUrl -> ResponseUtil.redirect(response, resUrl, promise))
|
||||||
|
.onFailure(t -> promise.fail(t.fillInStackTrace()));
|
||||||
return promise.future();
|
return promise.future();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,22 +52,6 @@ public class ServerApi {
|
|||||||
return IPanTool.shareURLPrefixMatching(url, pwd).parse();
|
return IPanTool.shareURLPrefixMatching(url, pwd).parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@RouteMapping(value = "/:type/:key", method = RouteMethod.GET, order = 1)
|
|
||||||
public void parseKey(HttpServerResponse response, String type, String key) {
|
|
||||||
String code = "";
|
|
||||||
if (key.contains("@")) {
|
|
||||||
String[] keys = key.split("@");
|
|
||||||
key = keys[0];
|
|
||||||
code = keys[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
IPanTool.typeMatching(type, key, code).parse().onSuccess(resUrl -> ResponseUtil.redirect(response, resUrl)).onFailure(t -> {
|
|
||||||
response.putHeader(CONTENT_TYPE, "text/html;charset=utf-8");
|
|
||||||
response.end(t.getMessage());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@RouteMapping(value = "/json/:type/:key", method = RouteMethod.GET, order = 2)
|
@RouteMapping(value = "/json/:type/:key", method = RouteMethod.GET, order = 2)
|
||||||
public Future<String> parseKeyJson(String type, String key) {
|
public Future<String> parseKeyJson(String type, String key) {
|
||||||
String code = "";
|
String code = "";
|
||||||
@@ -88,4 +62,21 @@ public class ServerApi {
|
|||||||
}
|
}
|
||||||
return IPanTool.typeMatching(type, key, code).parse();
|
return IPanTool.typeMatching(type, key, code).parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RouteMapping(value = "/:type/:key", method = RouteMethod.GET, order = 1)
|
||||||
|
public Future<Void> parseKey(HttpServerResponse response, String type, String key) {
|
||||||
|
Promise<Void> promise = Promise.promise();
|
||||||
|
String code = "";
|
||||||
|
if (key.contains("@")) {
|
||||||
|
String[] keys = key.split("@");
|
||||||
|
key = keys[0];
|
||||||
|
code = keys[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
IPanTool.typeMatching(type, key, code).parse()
|
||||||
|
.onSuccess(resUrl -> ResponseUtil.redirect(response, resUrl, promise))
|
||||||
|
.onFailure(t -> promise.fail(t.fillInStackTrace()));
|
||||||
|
return promise.future();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
package cn.qaiu.lz.web.model;
|
|
||||||
|
|
||||||
public class CowUser {
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
package cn.qaiu.lz.web.model;
|
|
||||||
|
|
||||||
public class LzUser {
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package cn.qaiu.lz.web.model;
|
||||||
|
|
||||||
|
import cn.qaiu.lz.common.ToJson;
|
||||||
|
import io.vertx.codegen.annotations.DataObject;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@DataObject
|
||||||
|
public class StatisticsInfo implements ToJson {
|
||||||
|
Integer fail;
|
||||||
|
Integer success;
|
||||||
|
Integer total;
|
||||||
|
|
||||||
|
|
||||||
|
public StatisticsInfo(JsonObject jsonObject) {
|
||||||
|
this.fail = jsonObject.getInteger("fail");
|
||||||
|
this.success = jsonObject.getInteger("success");
|
||||||
|
this.total = jsonObject.getInteger("total");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,22 +4,20 @@ import cn.qaiu.db.ddl.Table;
|
|||||||
import cn.qaiu.lz.common.ToJson;
|
import cn.qaiu.lz.common.ToJson;
|
||||||
import io.vertx.codegen.annotations.DataObject;
|
import io.vertx.codegen.annotations.DataObject;
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
@DataObject
|
@DataObject
|
||||||
|
@NoArgsConstructor
|
||||||
@Table("t_user")
|
@Table("t_user")
|
||||||
public class SysUser implements ToJson {
|
public class SysUser implements ToJson {
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
public SysUser(JsonObject json) {
|
public SysUser(JsonObject json) {
|
||||||
|
this.id = json.getString("id");
|
||||||
this.username = json.getString("username");
|
this.username = json.getString("username");
|
||||||
this.password = json.getString("password");
|
this.password = json.getString("password");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package cn.qaiu.lz.web.service;
|
package cn.qaiu.lz.web.service;
|
||||||
|
|
||||||
import cn.qaiu.lz.common.model.UserInfo;
|
import cn.qaiu.lz.common.model.UserInfo;
|
||||||
|
import cn.qaiu.lz.web.model.StatisticsInfo;
|
||||||
import cn.qaiu.vx.core.base.BaseAsyncService;
|
import cn.qaiu.vx.core.base.BaseAsyncService;
|
||||||
import io.vertx.codegen.annotations.ProxyGen;
|
import io.vertx.codegen.annotations.ProxyGen;
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
@@ -16,4 +17,6 @@ import io.vertx.core.json.JsonObject;
|
|||||||
public interface DbService extends BaseAsyncService {
|
public interface DbService extends BaseAsyncService {
|
||||||
Future<JsonObject> sayOk(String data);
|
Future<JsonObject> sayOk(String data);
|
||||||
Future<JsonObject> sayOk2(String data, UserInfo holder);
|
Future<JsonObject> sayOk2(String data, UserInfo holder);
|
||||||
|
|
||||||
|
Future<StatisticsInfo> getStatisticsInfo();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,5 +13,5 @@ import io.vertx.core.Future;
|
|||||||
*/
|
*/
|
||||||
@ProxyGen
|
@ProxyGen
|
||||||
public interface UserService extends BaseAsyncService {
|
public interface UserService extends BaseAsyncService {
|
||||||
Future<String> login(SysUser user);
|
Future<SysUser> login(SysUser user);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
package cn.qaiu.lz.web.service.impl;
|
package cn.qaiu.lz.web.service.impl;
|
||||||
|
|
||||||
|
import cn.qaiu.db.pool.JDBCPoolInit;
|
||||||
import cn.qaiu.lz.common.model.UserInfo;
|
import cn.qaiu.lz.common.model.UserInfo;
|
||||||
import cn.qaiu.lz.web.service.DbService;
|
import cn.qaiu.lz.web.service.DbService;
|
||||||
|
import cn.qaiu.lz.web.model.StatisticsInfo;
|
||||||
import cn.qaiu.vx.core.annotaions.Service;
|
import cn.qaiu.vx.core.annotaions.Service;
|
||||||
import cn.qaiu.vx.core.model.JsonResult;
|
import cn.qaiu.vx.core.model.JsonResult;
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
|
import io.vertx.core.Promise;
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.jdbcclient.JDBCPool;
|
||||||
|
import io.vertx.sqlclient.templates.SqlTemplate;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lz-web
|
* lz-web
|
||||||
* <br>Create date 2021/7/12 17:26
|
* <br>Create date 2021/7/12 17:26
|
||||||
@@ -35,4 +42,25 @@ public class DbServiceImpl implements DbService {
|
|||||||
// log.info("--> {}", holder.toString());
|
// log.info("--> {}", holder.toString());
|
||||||
return Future.succeededFuture(JsonObject.mapFrom(JsonResult.data("Hi: " + data)));
|
return Future.succeededFuture(JsonObject.mapFrom(JsonResult.data("Hi: " + data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Future<StatisticsInfo> getStatisticsInfo() {
|
||||||
|
JDBCPool client = JDBCPoolInit.instance().getPool();
|
||||||
|
Promise<StatisticsInfo> promise = Promise.promise();
|
||||||
|
String sql = """
|
||||||
|
select COUNT(CASE "code" WHEN 500 THEN "code" END ) "fail",
|
||||||
|
COUNT(CASE "code" WHEN 200 THEN "code" END ) "success",
|
||||||
|
count(1) "total"
|
||||||
|
from "t_parser_log_info"
|
||||||
|
""";
|
||||||
|
SqlTemplate.forQuery(client, sql).mapTo(StatisticsInfo.class).execute(new HashMap<>()).onSuccess(row -> {
|
||||||
|
StatisticsInfo info;
|
||||||
|
if ((info = row.iterator().next()) != null) {
|
||||||
|
promise.complete(info);
|
||||||
|
} else {
|
||||||
|
promise.fail("t_parser_log_info查询为空");
|
||||||
|
}
|
||||||
|
}).onFailure(promise::fail);
|
||||||
|
return promise.future();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ import java.util.concurrent.TimeUnit;
|
|||||||
public class UserServiceImpl implements UserService {
|
public class UserServiceImpl implements UserService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Future<String> login(SysUser user) {
|
public Future<SysUser> login(SysUser user) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
TimeUnit.SECONDS.sleep(6);
|
TimeUnit.SECONDS.sleep(2);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
return Future.succeededFuture("111");
|
return Future.succeededFuture(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ server:
|
|||||||
# 使用静态页面
|
# 使用静态页面
|
||||||
enableStaticHtmlService: false
|
enableStaticHtmlService: false
|
||||||
# 使用数据库
|
# 使用数据库
|
||||||
enableDatabase: false
|
enableDatabase: true
|
||||||
staticResourcePath: webroot/
|
staticResourcePath: webroot/
|
||||||
# 反向代理服务器配置路径(不用加后缀)
|
# 反向代理服务器配置路径(不用加后缀)
|
||||||
proxyConf: server-proxy
|
proxyConf: server-proxy
|
||||||
@@ -22,11 +22,9 @@ custom:
|
|||||||
baseLocations: cn.qaiu.lz
|
baseLocations: cn.qaiu.lz
|
||||||
# 路由处理默认超时时间(毫秒)
|
# 路由处理默认超时时间(毫秒)
|
||||||
routeTimeOut: 15000
|
routeTimeOut: 15000
|
||||||
# 拦截器包路径
|
|
||||||
interceptorClassPath: cn.qaiu.lz.common.interceptorImpl.DefaultInterceptor
|
|
||||||
# 拦截器匹配规则
|
# 拦截器匹配规则
|
||||||
ignoresReg:
|
ignoresReg:
|
||||||
- .*/login$
|
- /v2/statisticsInfo
|
||||||
- .*/test.*$
|
- .*/test.*$
|
||||||
|
|
||||||
# 参数注入的实体类包路径匹配正则 (防止同名类引发歧义)
|
# 参数注入的实体类包路径匹配正则 (防止同名类引发歧义)
|
||||||
@@ -37,11 +35,7 @@ custom:
|
|||||||
# 数据源配置
|
# 数据源配置
|
||||||
dataSource:
|
dataSource:
|
||||||
provider_class: io.vertx.ext.jdbc.spi.impl.HikariCPDataSourceProvider
|
provider_class: io.vertx.ext.jdbc.spi.impl.HikariCPDataSourceProvider
|
||||||
jdbcUrl: jdbc:h2:tcp://127.0.0.1:9095/./db/myData;MODE=MySQL;DATABASE_TO_LOWER=FALSE
|
jdbcUrl: jdbc:h2:tcp://127.0.0.1:9095/./db/myData;MODE=MySQL;DATABASE_TO_UPPER=FALSE
|
||||||
driverClassName: org.h2.Driver
|
driverClassName: org.h2.Driver
|
||||||
username: root
|
username: root
|
||||||
password: '123456'
|
password: '123456'
|
||||||
tableClassPath: cn.qaiu.lz.web.model
|
|
||||||
|
|
||||||
cowConfig:
|
|
||||||
config: '111'
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# 要激活的配置: dev--连接本地数据库; prod连接线上数据库
|
# 要激活的配置: dev--连接本地数据库; prod连接线上数据库
|
||||||
active: dev
|
active: dev
|
||||||
# 版本号
|
# 版本号
|
||||||
version_app: 0.1.6
|
version_app: 0.1.7
|
||||||
# 公司名称 -> LOGO版权文字
|
# 公司名称 -> LOGO版权文字
|
||||||
copyright: QAIU
|
copyright: QAIU
|
||||||
|
|||||||
19
web-service/src/main/resources/http-tools/pan-ce.http
Normal file
19
web-service/src/main/resources/http-tools/pan-ce.http
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
###
|
||||||
|
https://5jmpj3-my.sharepoint.com/personal/pan2_xiaomuxi_cn/_layouts/15/download.aspx?UniqueId=cf123281-44cd-4745-b3c3-49a18934044d&Translate=false&tempauth=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIwMDAwMDAwMy0wMDAwLTBmZjEtY2UwMC0wMDAwMDAwMDAwMDAvNWptcGozLW15LnNoYXJlcG9pbnQuY29tQGY4MTk4OWJiLWViNDAtNGZhYi05NzA5LTQ0ODFhMDM0ZjNiNCIsImlzcyI6IjAwMDAwMDAzLTAwMDAtMGZmMS1jZTAwLTAwMDAwMDAwMDAwMCIsIm5iZiI6IjE3MDY0MzIyNDciLCJleHAiOiIxNzA2NDM1ODQ3IiwiZW5kcG9pbnR1cmwiOiJNMWVwZ3VjamFKU081MXB4WW5IKzZ6bzZBQlVyc0N1T3MwOVRGbnZJVlRvPSIsImVuZHBvaW50dXJsTGVuZ3RoIjoiMTQ2IiwiaXNsb29wYmFjayI6IlRydWUiLCJjaWQiOiJKM0JzNzloTy8wYW1GZGh1WUFjTjR3PT0iLCJ2ZXIiOiJoYXNoZWRwcm9vZnRva2VuIiwic2l0ZWlkIjoiWkRkaVptRTBNRFl0TXpWall5MDBZamMxTFRsbU16TXRNRGc0TlRCbVkyRmlPVE0yIiwiYXBwX2Rpc3BsYXluYW1lIjoiMuWPt-WtmOWCqOehrOebmCIsImdpdmVuX25hbWUiOiIy5Y-3IiwiZmFtaWx5X25hbWUiOiLnvZHnm5giLCJhcHBpZCI6ImJkZDRjOTA5LTA0ZjItNDU4NS04MjZlLTY0MDQzNDljN2JiZiIsInRpZCI6ImY4MTk4OWJiLWViNDAtNGZhYi05NzA5LTQ0ODFhMDM0ZjNiNCIsInVwbiI6InBhbjJAeGlhb211eGkuY24iLCJwdWlkIjoiMTAwMzIwMDJBRTUyNDMwRCIsImNhY2hla2V5IjoiMGguZnxtZW1iZXJzaGlwfDEwMDMyMDAyYWU1MjQzMGRAbGl2ZS5jb20iLCJzY3AiOiJhbGxmaWxlcy53cml0ZSIsInR0IjoiMiIsImlwYWRkciI6IjIwLjE5MC4xNDQuMTcxIn0.WY--gv_Ac1pwhj3XTOdIddaj643CHoOqBeFFpdSa4-w&ApiVersion=2.0
|
||||||
|
|
||||||
|
###
|
||||||
|
#@no-redirect
|
||||||
|
PUT https://pan.xiaomuxi.cn/api/v3/share/download/Ag4Uy
|
||||||
|
|
||||||
|
###
|
||||||
|
PUT https://pan.huang1111.cn/api/v3/share/download/m1Mlt1
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
https://pan.huang1111.cn/api/v3/share/info/g31PcQ?password=qaiu
|
||||||
|
|
||||||
|
###
|
||||||
|
https://pan.huang1111.cn/api/v3/share/info/m1Mlt1?password=
|
||||||
|
|
||||||
|
###
|
||||||
|
PUT https://pan.huang1111.cn/api/v3/share/download/g31PcQ?path=undefined%2Fundefined
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
# offset: 1
|
# offset: 1
|
||||||
# limit: 60
|
# limit: 60
|
||||||
# @no-cookie-jar
|
# @no-cookie-jar
|
||||||
POST https://api.feijipan.com/ws/recommend/list?devType=6&devModel=Chrome&extra=2&shareId=193186&type=0&offset=1&limit=60
|
POST https://api.feijipan.com/ws/recommend/list?devType=6&devModel=Chrome&extra=2&shareId=146731&type=0&offset=1&limit=60
|
||||||
|
|
||||||
# 654488C79332E7279F9A38367BD72D3B
|
# 654488C79332E7279F9A38367BD72D3B
|
||||||
# 4703B103BD6871F83441233393695EF3
|
# 4703B103BD6871F83441233393695EF3
|
||||||
@@ -37,4 +37,25 @@ https://web.feejii.com/ee433d6e5102ad79af58a2aa0e6cf758/1686279412/files/2023/05
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 7jy0zlv
|
||||||
|
https://api.feijipan.com/ws/recommend/list?devType=6&devModel=Chrome&extra=2&shareId=146731
|
||||||
|
|
||||||
###
|
###
|
||||||
|
# @no-redirect
|
||||||
|
https://api.feijipan.com/ws/file/redirect?downloadId=4703B103BD6871F83441233393695EF3&enable=1&devType=6&uuid=ZIdOV27C5dHvd3aUUXoiP×tamp=4FDB14DD6441E581458CD2750EAF188A&auth=42965E158C74872285C5A3F545118CAAF417B148DBEEBF90B0969E08950830E5
|
||||||
|
Referer: https://share.feijipan.com/
|
||||||
|
|
||||||
|
###
|
||||||
|
# @no-redirect
|
||||||
|
https://api.feijipan.com/ws/file/redirect?uuid=6591af86-5464-4c8d-a100-44f6cb859e9b&devType=6&devCode=6591af86-5464-4c8d-a100-44f6cb859e9b&devModel=chrome&devVersion=122&appVersion=×tamp=77d605733113552383e2626fe134cfc3&appToken=9a253a6202bc1095030a8e8d76fe7f38-1&enable=1&downloadId=79d91c3dc8b578d4c69b04b8251f04e029de3c08240dc9ceab77f7f656cbba23&auth=ccfd80a4787abfb1b86970902e3156ff155ae85ef80ebd661d3bc33de20659a1
|
||||||
|
Referer: https://share.feijipan.com/
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
POST https://api.feijipan.com/ws/login?uuid=6591af86-5464-4c8d-a100-44f6cb859e9b&devType=6&devCode=6591af86-5464-4c8d-a100-44f6cb859e9b&devModel=chrome&devVersion=122&appVersion=×tamp=2e6932b46c0bc20d9cbcdb6c5f0e9bee&appToken=&extra=2
|
||||||
|
Accept:application/json, text/plain, */*
|
||||||
|
Content-Type:application/json
|
||||||
|
Origin:https://www.feijipan.com
|
||||||
|
Referer:https://www.feijipan.com/
|
||||||
|
|
||||||
|
{"loginName":"15687886400","loginPwd":"4458225ff"}
|
||||||
|
|||||||
27
web-service/src/main/resources/http-tools/pan-iz.http
Normal file
27
web-service/src/main/resources/http-tools/pan-iz.http
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
###
|
||||||
|
POST https://api.ilanzou.com/unproved/recommend/list?shareId=26216
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
#@no-redirect
|
||||||
|
https://api.ilanzou.com/unproved/file/redirect?downloadId=DC3D647979EE315935D1687834F05914&enable=1&devType=6&uuid=46vk1ImPHKt1Mr2cRu5wA×tamp=B11E6A597CB93B55D87A338AEDDFBE45&auth=8BF7415F1AA0BB02278336F3C11EBD0B25654EAAB68588D5E8C4974ACAD88935
|
||||||
|
|
||||||
|
###
|
||||||
|
#@no-redirect
|
||||||
|
https://api.ilanzou.com/unproved/file/redirect?downloadId=DC3D647979EE315935D1687834F05914&enable=1&devType=6&uuid=46vk1ImPHKt1Mr2cRu5wA×tamp=90A417B68D70B35311FACC72EEE63291&auth=849E8A34873CA37147A5FE110912FCBF836D8BD5D37626FBCBD8A3F6F42A7A8B
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
#@no-redirect
|
||||||
|
https://dl.lanosso.com/disk/2024/01/28/9/14733029/1706414002788330.gz?attname=testgles.c&sign=9ef76e9a270dbe5e9401c8f4c2ae0d68&t=65b5f826
|
||||||
|
|
||||||
|
###
|
||||||
|
#@no-redirect
|
||||||
|
https://api.ilanzou.com/unproved/file/redirect?uuid=0&devType=6×tamp=4532409118d790651b6b50823bf6a555&downloadId=d16fcb8f3e00da0eb956db9a0541f97277437b80f7fe61438b7fba55856e050f&auth=a4c567681b3ba556b5d70cff93e909774a6695647300260c5f0abfe3c188f1a0
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
https://www.ilanzou.com/s/zHkna1S
|
||||||
|
|
||||||
|
### fileId: 145042258
|
||||||
17
web-service/src/main/resources/http-tools/pan-jg.http
Normal file
17
web-service/src/main/resources/http-tools/pan-jg.http
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
### 坚果云直链
|
||||||
|
GET https://www.jianguoyun.com/c/dl-file/bin.zip?dt=s80etr&sd=ekfj3&kv=NzM2MjI2NDAwQHFxLmNvbQ&vr=1&ud=Ai4TqB3nzfSF6iR0zapyvKGPYKP_cUqKIhtziVb1dRA
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
https://www.jianguoyun.com/d/ajax/dlink?sndId=175599f&sndMagic=2d8381e894e47b39&path=%2Fbin.zip&forwin=true&_=1706507895357
|
||||||
|
Cookie:umn=736226400%40qq.com; ta=G0RPJtiW0%2FEqRmv4amZpcXTLHhuOxhQCSTJX3IU5HVo%3D;
|
||||||
|
|
||||||
|
###
|
||||||
|
https://www.jianguoyun.com/d/ajax/fileops/pubFileLink?k=DSBBfXkQn7PVCxjz24cFIAA
|
||||||
|
Cookie:umn=736226400%40qq.com; ta=G0RPJtiW0%2FEqRmv4amZpcXTLHhuOxhQCSTJX3IU5HVo%3D;
|
||||||
|
|
||||||
|
###
|
||||||
|
https://www.jianguoyun.com/d/signup?next=%2Fp%2FDSBBfXkQn7PVCxjz24cFIAA&msg=%E7%99%BB%E5%BD%95%E5%90%8E%E7%AB%8B%E5%8D%B3%E4%B8%8B%E8%BD%BD%E6%96%87%E4%BB%B6
|
||||||
118
web-service/src/main/resources/http-tools/pan-le.http
Normal file
118
web-service/src/main/resources/http-tools/pan-le.http
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
// 联想乐云(联想云服务)
|
||||||
|
|
||||||
|
### 第一步 https://lecloud.lenovo.com/share/4DANWdRQsHHyiFB4a
|
||||||
|
POST https://lecloud.lenovo.com/share/api/clouddiskapi/share/public/v1/shareInfo
|
||||||
|
Content-Type:application/json;charset=UTF-8
|
||||||
|
|
||||||
|
{"shareId":"4DANWdRQsHHyiFB4a","password":"","directoryId":"-1"}
|
||||||
|
|
||||||
|
### res
|
||||||
|
#{
|
||||||
|
# "result": true,
|
||||||
|
# "data": {
|
||||||
|
# "senderUserName": "7362264*****.com",
|
||||||
|
# "validSecondsLeft": -1,
|
||||||
|
# "memo": "",
|
||||||
|
# "passwordVerified": true,
|
||||||
|
# "files": [
|
||||||
|
# {
|
||||||
|
# "fileType": 99,
|
||||||
|
# "fileId": 12298705,
|
||||||
|
# "fileName": "classes.dex",
|
||||||
|
# "fileSize": 8909208
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
|
# }
|
||||||
|
#}
|
||||||
|
|
||||||
|
#{
|
||||||
|
# "result": false,
|
||||||
|
# "errcode": "SHARE_ID_INVALID",
|
||||||
|
# "errmsg": "分享ID无效"
|
||||||
|
#}
|
||||||
|
|
||||||
|
###
|
||||||
|
# @name 第二步
|
||||||
|
POST https://lecloud.lenovo.com/share/api/clouddiskapi/share/public/v1/packageDownloadWithFileIds
|
||||||
|
Content-Type:application/json;charset=UTF-8
|
||||||
|
|
||||||
|
{"fileIds":[12299013],"shareId":"2RkKbLP9BrppS9b43","browserId":"asdddsad"}
|
||||||
|
|
||||||
|
###
|
||||||
|
#{
|
||||||
|
# "result": true,
|
||||||
|
# "data": {
|
||||||
|
# "downloadUrl": "https://pimapi.lenovomm.com/clouddiskapi/v1/shareRedirect?si=12299012&dk=b9d2870c001b56f6b23f6036fd049b237b3b3d47c0dbd30513ddaa7137cd64c9&pk=5a69c8b5f3835171b01ad866241de857d02c8b6e4985e51d652ab1bf331a3ae0&pc=true&ot=ali&ob=sync-cloud-disk&ok=649599424036290560.zip&fn=c4droid_aarch64_gcc11_new.zip&ds=140596045&dc=1&bi=asdddsad&ri=&ts=1701156293620&sn=b9dd3816eb1fd7743f5fa904986c15cb36fd9c08b4fbe0d94d198bd2bbf7c5be"
|
||||||
|
# }
|
||||||
|
#}
|
||||||
|
|
||||||
|
#{
|
||||||
|
# "result": false,
|
||||||
|
# "errcode": "FILE_NOT_EXIST",
|
||||||
|
# "errmsg": "文件不存在"
|
||||||
|
#}
|
||||||
|
|
||||||
|
###
|
||||||
|
# @name 第三步 302跳转链接
|
||||||
|
# @no-redirect
|
||||||
|
https://pimapi.lenovomm.com/clouddiskapi/v1/shareRedirect?si=12298704&dk=ad0ef0fe93134baf6850294701e96986b1b933231c346589ccd635520908ebec&pk=ef45aa4d25c1dcecb631b3394f51539d59cb35c6a40c3911df8ba431ba2a3244&pc=true&ot=ali&ob=sync-cloud-disk&ok=649593714557087744.dex&fn=classes.dex&ds=8909208&dc=1&bi=asdddsad&ri=&ts=1701235051759&sn=30589173efacb5b493fd47e0f134309ab598252951a5a82d8292011e626b5c26
|
||||||
|
###
|
||||||
|
# @no-redirect
|
||||||
|
https://pimapi.lenovomm.com/clouddiskapi/v1/shareRedirect?si=12299012&dk=b9d2870c001b56f6b23f6036fd049b237b3b3d47c0dbd30513ddaa7137cd64c9&pk=5a69c8b5f3835171b01ad866241de857d02c8b6e4985e51d652ab1bf331a3ae0&pc=true&ot=ali&ob=sync-cloud-disk&ok=649599424036290560.zip&fn=c4droid_aarch64_gcc11_new.zip&ds=140596045&dc=1&bi=asdddsad&ri=&ts=1701234891872&sn=89ba38f2ca09238d284f723449a0b8af02b1a933a6bc1ee9ee71cc373d7b6a59
|
||||||
|
###
|
||||||
|
# @no-redirect
|
||||||
|
https://pimapi.lenovomm.com/clouddiskapi/v1/shareRedirect?si=12298704&dk=19ab590770399d4438ea885446e27186cc668cdfa559f5fcc063a1ecf78008e5&pk=ef45aa4d25c1dcecb631b3394f51539d59cb35c6a40c3911df8ba431ba2a3244&pc=true&ot=ali&ob=sync-cloud-disk&ok=649593714557087744.dex&fn=classes.dex&ds=8909208&dc=1&bi=asdddsad&ri=&ts=1701235051759&sn=13dc33749bd9cc108009fa505b3ecca9f358d70874352858475956ba4240e4c3
|
||||||
|
###
|
||||||
|
# @no-redirect
|
||||||
|
https://pimapi.lenovomm.com/clouddiskapi/v1/shareRedirect?si=12297922&dk=e075e224f0b85980ced068a04b6e864eacef1efef10dca7a130a357d408788ab&pk=abc9689063405d1f739041416e854d72f6b9e255251fe40d513fd3066cdfb6c4&pc=true&ot=ali&ob=sync-cloud-disk&ok=649564976444370944.exe&fn=%E8%87%B4%E4%BF%A1_20220601.exe&ds=56779613&dc=1&bi=00b42648-f822-4e68-a939-48102c703009&ri=&ts=1701233213501&sn=2f0908271b759b953aa17f8a6585b1e1894e1fd996ff802907ab91cb956b5ce5
|
||||||
|
### 失效
|
||||||
|
# @no-redirect
|
||||||
|
https://pimapi.lenovomm.com/clouddiskapi/v1/shareRedirect?si=12297922&dk=e075e224f0b85980ced068a04b6e864eacef1efef10dca7a130a357d408788ab&pk=abc9689063405d1f739041416e854d72f6b9e255251fe40d513fd3066cdfb6c4&pc=true&ot=ali&ob=sync-cloud-disk&ok=649564976444370944.exe&fn=%E8%87%B4%E4%BF%A1_20220601.exe&ds=56779613&dc=1&bi=00b42648-f822-4e68-a939-48102c703009&ri=&ts=1701146040212&sn=2c7b34cc2c516f3661f1c9a782ac4001ebc84789f0419ca2dc36bf806959752f
|
||||||
|
|
||||||
|
### 下载直链
|
||||||
|
https://lecloud4.lenovomm.cn/dlserver/fileman/ali/sync-cloud-disk/649593714557087744.dex?KEY1=7be0212f4bd3155951942d9d62b8dfd9&KEY2=65681948&fn=classes.dex
|
||||||
|
###
|
||||||
|
https://lecloud4.lenovomm.cn/dlserver/fileman/ali/sync-cloud-disk/649593714557087744.dex?KEY1=d602d76dffd9914459a1f535585a330f&KEY2=656974EC&fn=classes.dex
|
||||||
|
###
|
||||||
|
https://lecloud4.lenovomm.cn/dlserver/fileman/ali/sync-cloud-disk/649593714557087744.dex?KEY1=89938873f9adcce3d543c178a128de10&KEY2=65697528&fn=classes.dex
|
||||||
|
|
||||||
|
###
|
||||||
|
https://lecloud4.lenovomm.cn/dlserver/fileman/ali/sync-cloud-disk/649593714557087744.dex?KEY1=efc1335ae0b77555dcf55aa1ab78c2a7&KEY2=656811B8&fn=classes.dex
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### https://lecloud.lenovo.com/share/2RkKbLP9BrppS9b43(密码:ex2b)
|
||||||
|
POST https://lecloud.lenovo.com/share/api/clouddiskapi/share/public/v1/shareInfo
|
||||||
|
Content-Type:application/json;charset=UTF-8
|
||||||
|
|
||||||
|
{"shareId":"2RkKbLP9BrppS9b43","password":"ex2b","directoryId":"-1"}
|
||||||
|
|
||||||
|
### 错误Result
|
||||||
|
#{
|
||||||
|
# "result": true,
|
||||||
|
# "data": {
|
||||||
|
# "senderUserName": "7362264*****.com",
|
||||||
|
# "validSecondsLeft": -1,
|
||||||
|
# "memo": "tttttt",
|
||||||
|
# "passwordVerified": false
|
||||||
|
# }
|
||||||
|
#}
|
||||||
|
|
||||||
|
###
|
||||||
|
# @name https://lecloud.lenovo.com/share/2RXy2r8odVJtnWMSN
|
||||||
|
POST https://lecloud.lenovo.com/share/api/clouddiskapi/share/public/v1/shareInfo
|
||||||
|
Content-Type:application/json;charset=UTF-8
|
||||||
|
|
||||||
|
{"shareId":"2RXy2r8odVJtnWMSN","password":"","directoryId":"-1"}
|
||||||
|
|
||||||
|
###
|
||||||
|
# @name 第二步
|
||||||
|
POST https://lecloud.lenovo.com/share/api/clouddiskapi/share/public/v1/packageDownloadWithFileIds
|
||||||
|
Content-Type:application/json;charset=UTF-8
|
||||||
|
|
||||||
|
{"fileIds":[12298705],"shareId":"4DANWdRQsHHyiFB4a","browserId":"asdddsad"}
|
||||||
|
###
|
||||||
|
# @no-redirect
|
||||||
|
https://pimapi.lenovomm.com/clouddiskapi/share/public/v1/createPayOrder?dk=6678fff6cb83cdc545db42f1b4d6df7302c1878780647d67c218d74df6b8193e
|
||||||
@@ -4,11 +4,14 @@ GET http://127.0.0.1:6400/parser?url=https://lanzoux.com/ia2cntg
|
|||||||
|
|
||||||
### 蓝奏云
|
### 蓝奏云
|
||||||
# @no-redirect
|
# @no-redirect
|
||||||
GET http://127.0.0.1:6400/parser?url=https://lanzoux.com/iNvid035jgcb
|
GET http://127.0.0.1:6400/json/parser?url=https://wwsd.lanzoue.com/iLany1e9bbbi
|
||||||
|
|
||||||
### 蓝奏云
|
### 蓝奏云
|
||||||
# @no-redirect
|
# @no-redirect
|
||||||
GET http://127.0.0.1:6400/lz/i6SqHmp1yfc
|
GET http://127.0.0.1:6400/lz/i6SqHmp1yfc
|
||||||
|
### 蓝奏云https://acgtools.lanzoui.com/iUr7Qnu3sxc https://wwn.lanzouy.com/tp/ihLkw1gezutg https://wwn.lanzouy.com/ihLkw1gezutg
|
||||||
|
# @no-redirect
|
||||||
|
GET http://127.0.0.1:6400/lz/ihLkw1gezutg
|
||||||
|
|
||||||
### 蓝奏云
|
### 蓝奏云
|
||||||
# @no-redirect
|
# @no-redirect
|
||||||
@@ -17,12 +20,24 @@ GET http://127.0.0.1:6400/lz/icBp6qqj82b@QAIU
|
|||||||
### 蓝奏云
|
### 蓝奏云
|
||||||
GET http://127.0.0.1:6400/json/lz/ia2cntg
|
GET http://127.0.0.1:6400/json/lz/ia2cntg
|
||||||
|
|
||||||
|
### 蓝奏云优享
|
||||||
|
GET http://127.0.0.1:6400/json/iz/lGFndCM
|
||||||
|
|
||||||
|
###
|
||||||
|
GET http://127.0.0.1:6400/json/parser?url=https://www.ilanzou.com/s/lGFndCM
|
||||||
|
###
|
||||||
|
GET http://127.0.0.1:6400/json/parser?url=https://www.ilanzou.com/s/6XwnC4X
|
||||||
|
###
|
||||||
|
GET http://127.0.0.1:6400/json/parser?url=https://www.ilanzou.com/s/zHkna1S
|
||||||
|
|
||||||
### 奶牛
|
### 奶牛
|
||||||
GET http://127.0.0.1:6400/json/cow/9a644fe3e3a748
|
GET http://127.0.0.1:6400/json/cow/9a644fe3e3a748
|
||||||
|
Referer: https://cowtransfer.com/
|
||||||
|
|
||||||
### 奶牛
|
### 奶牛
|
||||||
# @no-redirect
|
# @no-redirect
|
||||||
GET http://127.0.0.1:6400/cow/e4f41b51b5da4f
|
GET http://127.0.0.1:6400/cow/e4f41b51b5da4f
|
||||||
|
Referer: https://cowtransfer.com/
|
||||||
|
|
||||||
### 奶牛
|
### 奶牛
|
||||||
# @no-redirect
|
# @no-redirect
|
||||||
@@ -56,12 +71,17 @@ GET http://127.0.0.1:6400/json/uc/33197dd53ace4
|
|||||||
GET http://127.0.0.1:6400/parser?url=https://fast.uc.cn/s/33197dd53ace4
|
GET http://127.0.0.1:6400/parser?url=https://fast.uc.cn/s/33197dd53ace4
|
||||||
|
|
||||||
|
|
||||||
### 小飞机盘
|
### 小飞机盘https://share.feijipan.com/s/nMtCOXL
|
||||||
# @no-redirect
|
# @no-redirect
|
||||||
GET http://127.0.0.1:6400/parser?url=https://www.feijix.com/s/tIfhRqH
|
GET http://127.0.0.1:6400/parser?url=https://share.feijipan.com/s/nMtCOXL
|
||||||
|
|
||||||
|
### 小飞机盘 https://share.feijipan.com/s/laUshYGk
|
||||||
|
# @no-redirect
|
||||||
|
GET http://127.0.0.1:6400/parser?url=https://share.feijipan.com/s/laUshYGk
|
||||||
### 小飞机盘
|
### 小飞机盘
|
||||||
GET http://127.0.0.1:6400/json/fj/tIfhRqH
|
GET http://127.0.0.1:6400/json/fj/tIfhRqH
|
||||||
|
### 小飞机盘 https://share.feijipan.com/s/7jy0zlv
|
||||||
|
GET http://127.0.0.1:6400/json/fj/7jy0zlv
|
||||||
|
|
||||||
### 小飞机盘
|
### 小飞机盘
|
||||||
# @no-redirect
|
# @no-redirect
|
||||||
@@ -93,11 +113,47 @@ GET https://lz.qaiu.top/json/ye/iaKtVv-6OECd@DcGe
|
|||||||
# @no-redirect
|
# @no-redirect
|
||||||
GET http://127.0.0.1:6400/ye/iaKtVv-qOECd
|
GET http://127.0.0.1:6400/ye/iaKtVv-qOECd
|
||||||
|
|
||||||
|
### 123
|
||||||
|
# @no-redirect
|
||||||
|
GET http://127.0.0.1:6400/ye/Ev1lVv-t3SY3
|
||||||
|
|
||||||
### 123
|
### 123
|
||||||
# @no-redirect
|
# @no-redirect
|
||||||
GET http://127.0.0.1:6400/parser?url=https://www.123pan.com/s/iaKtVv-6OECd.html&pwd=DcGe
|
GET http://127.0.0.1:6400/parser?url=https://www.123pan.com/s/iaKtVv-6OECd.html&pwd=DcGe
|
||||||
|
|
||||||
|
|
||||||
|
### 123
|
||||||
|
# @no-redirect
|
||||||
|
GET http://127.0.0.1:6400/parser?url=https://www.123pan.com/s/zF07Vv-WkHWd.html&pwd=bios
|
||||||
|
|
||||||
|
|
||||||
|
### 联想乐云
|
||||||
|
# @no-redirect
|
||||||
|
GET http://127.0.0.1:6400/parser?url=https://lecloud.lenovo.com/share/4DANWdRQsHHyiFB4a
|
||||||
|
|
||||||
|
### 联想乐云
|
||||||
|
# @no-redirect
|
||||||
|
GET http://127.0.0.1:6400/le/4DANWdRQsHHyiFB4a
|
||||||
|
|
||||||
|
### 联想乐云
|
||||||
|
# @no-redirect
|
||||||
|
GET http://127.0.0.1:6400/le/2RkKbLP9BrppS9b43@ex2b
|
||||||
|
|
||||||
|
### 联想乐云
|
||||||
|
GET http://127.0.0.1:6400/json/le/2RkKbLP9BrppS9b43@ex2b
|
||||||
|
|
||||||
|
### Cloudreve
|
||||||
|
GET http://127.0.0.1:6400/json/ce/https_pan.huang1111.cn_s_wDz5TK
|
||||||
|
|
||||||
|
### Cloudreve
|
||||||
|
GET http://127.0.0.1:6400/json/parser?url=https://pan.huang1111.cn/s/g31PcQ&pwd=qaiu
|
||||||
|
|
||||||
###
|
###
|
||||||
POST http://127.0.0.1:6400/login
|
GET http://127.0.0.1:6400/v2/statisticsInfo
|
||||||
|
|
||||||
|
###
|
||||||
|
POST http://127.0.0.1:6400/v2/login?username=asd
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
|
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
|
||||||
<!-- 日志自定义颜色 -->
|
<!-- 日志自定义颜色 -->
|
||||||
<!-- https://logback.qos.ch/manual/layouts.html#coloring -->
|
<!-- https://logback.qos.ch/manual/layouts.html#coloring -->
|
||||||
|
|
||||||
@@ -46,6 +46,7 @@
|
|||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<withJansi>false</withJansi>
|
||||||
<encoder>
|
<encoder>
|
||||||
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
|
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
|
||||||
<pattern>${CUSTOMER_PATTERN2}</pattern>
|
<pattern>${CUSTOMER_PATTERN2}</pattern>
|
||||||
@@ -54,7 +55,7 @@
|
|||||||
<logger name="io.netty" level="warn"/>
|
<logger name="io.netty" level="warn"/>
|
||||||
<logger name="io.vertx" level="info"/>
|
<logger name="io.vertx" level="info"/>
|
||||||
<logger name="com.zaxxer.hikari" level="info"/>
|
<logger name="com.zaxxer.hikari" level="info"/>
|
||||||
<root level="debug">
|
<root level="info">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
<!-- <appender-ref ref="FILE"/>-->
|
<!-- <appender-ref ref="FILE"/>-->
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package cn.qaiu.vx.core.util;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class ParamUtilTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void paramsToMap() {
|
||||||
|
System.out.println(ParamUtil.paramsToMap(""));
|
||||||
|
System.out.println(ParamUtil.paramsToMap("a=asd&d=23"));
|
||||||
|
System.out.println(ParamUtil.paramsToMap("asdasd&dd"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import javassist.bytecode.LocalVariableAttribute;
|
|||||||
import javassist.bytecode.MethodInfo;
|
import javassist.bytecode.MethodInfo;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -82,4 +83,14 @@ public class Test02 {
|
|||||||
System.out.println(map);
|
System.out.println(map);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test4() {
|
||||||
|
LocalDateTime parse = LocalDateTime.parse((String) "2022-01-01T11:22:00");
|
||||||
|
System.out.println(parse);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user