mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2026-04-11 19:36:54 +00:00
Compare commits
359 Commits
v0.1.9b16
...
cb9dbfcc69
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb9dbfcc69 | ||
|
|
42b366ed0f | ||
|
|
4021c507b6 | ||
|
|
4d8e82080d | ||
|
|
fca608b44e | ||
|
|
34cb89a6ea | ||
|
|
69d5f269bd | ||
|
|
459c974cb8 | ||
|
|
2f22cb01eb | ||
|
|
e17fb99de4 | ||
|
|
0f926a57ef | ||
|
|
4380bfe0d6 | ||
|
|
8127cd0758 | ||
|
|
71a220f42b | ||
|
|
d3b02676ec | ||
|
|
d8f0dc4f8e | ||
|
|
48aa5b6148 | ||
|
|
a989841a89 | ||
|
|
86783e8e46 | ||
|
|
66b9bcc53a | ||
|
|
ff08615d1e | ||
|
|
4a6c3a1f90 | ||
|
|
c79702eba8 | ||
|
|
41fc935c09 | ||
|
|
5fbbe5b240 | ||
|
|
9c121c03f2 | ||
|
|
b74c3f31c4 | ||
|
|
f23b97e22c | ||
|
|
0560989e77 | ||
|
|
f2c9c34324 | ||
|
|
a97268c702 | ||
|
|
2654b550fb | ||
|
|
12a5a17a30 | ||
|
|
e346812c0a | ||
|
|
6b2e391af9 | ||
|
|
199456cb11 | ||
|
|
636994387f | ||
|
|
90c79f7bac | ||
|
|
79601b36a5 | ||
|
|
96cef89f08 | ||
|
|
e057825b25 | ||
|
|
ebe848dfe8 | ||
|
|
e259a0989e | ||
|
|
f750aa68e8 | ||
|
|
49b8501e86 | ||
|
|
fc2e2a4697 | ||
|
|
b4b1d7f923 | ||
|
|
df646b8c43 | ||
|
|
8e790f6b22 | ||
|
|
2e76af980e | ||
|
|
80ccbe5b62 | ||
|
|
aa0cd68f7f | ||
|
|
51833148b1 | ||
|
|
0fa77ebf21 | ||
|
|
584c075930 | ||
|
|
9e7a3718a4 | ||
|
|
0e2ca2f1ca | ||
|
|
52e889333b | ||
|
|
4745440079 | ||
|
|
b5628eac17 | ||
|
|
d23b11577e | ||
|
|
f1dd9fc0ee | ||
|
|
0877fadcfb | ||
|
|
733059dc8e | ||
|
|
321380c2b9 | ||
|
|
deb121a51b | ||
|
|
b6aef7c239 | ||
|
|
b13a7a5ee1 | ||
|
|
fff6a00690 | ||
|
|
b4da3cee20 | ||
|
|
0a650996a1 | ||
|
|
37b91cd388 | ||
|
|
42b721eabf | ||
|
|
231d5c3fb9 | ||
|
|
064efdf3f3 | ||
|
|
7b364a0f90 | ||
|
|
c8a4ca7f16 | ||
|
|
97627b824c | ||
|
|
6dbdc9bd90 | ||
|
|
4166ea10af | ||
|
|
fa12ab2c51 | ||
|
|
4fc4ed8640 | ||
|
|
48172f2769 | ||
|
|
c7e6d68fbd | ||
|
|
e6672a51c5 | ||
|
|
abde7841ac | ||
|
|
8e661ed1c5 | ||
|
|
217cb3a776 | ||
|
|
b8c1bca900 | ||
|
|
5e09b8e92a | ||
|
|
c16bde6bb8 | ||
|
|
eb06eb9f3d | ||
|
|
0c49088098 | ||
|
|
b970241a64 | ||
|
|
6c5aafc11e | ||
|
|
ca0846f4a7 | ||
|
|
14f7fcc5ad | ||
|
|
23a18aba5c | ||
|
|
2d5a79bb16 | ||
|
|
51e1bbefbb | ||
|
|
6647fc5371 | ||
|
|
b67544f0cd | ||
|
|
ef5826a73b | ||
|
|
a48adbd0df | ||
|
|
5c60493a24 | ||
|
|
55e6227de0 | ||
|
|
24a7395004 | ||
|
|
b2a7187fc5 | ||
|
|
ace7cdc88e | ||
|
|
2e909b5868 | ||
|
|
de78bcbc98 | ||
|
|
c560f0e902 | ||
|
|
88860c9302 | ||
|
|
ef65d0e095 | ||
|
|
6438505f4a | ||
|
|
1be5030dd1 | ||
|
|
421b2f4a42 | ||
|
|
a66bf84381 | ||
|
|
0c4d366d6d | ||
|
|
a1d0a921fa | ||
|
|
2092230a61 | ||
|
|
6e5ae6eff3 | ||
|
|
4f8259d772 | ||
|
|
8b987d9824 | ||
|
|
e8ba451d18 | ||
|
|
77758db463 | ||
|
|
6c58598a8e | ||
|
|
3ac35230a3 | ||
|
|
ca91302d28 | ||
|
|
e07272a5dc | ||
|
|
461305e1df | ||
|
|
8e8ab10a0f | ||
|
|
e754326925 | ||
|
|
4c92994c6f | ||
|
|
66c57f47ac | ||
|
|
ec689eadd8 | ||
|
|
c1e15709a7 | ||
|
|
2848937ce7 | ||
|
|
42ff0c21b2 | ||
|
|
3ed7e547e6 | ||
|
|
fad8e688df | ||
|
|
b2f2dcac4c | ||
|
|
fcba78e977 | ||
|
|
77c9d777a1 | ||
|
|
4460659210 | ||
|
|
8631524107 | ||
|
|
0579588814 | ||
|
|
df2bfb6ac7 | ||
|
|
517b6f8910 | ||
|
|
94a46d2833 | ||
|
|
1631a0faa1 | ||
|
|
06d5943cb6 | ||
|
|
3095e13676 | ||
|
|
482cbce7e8 | ||
|
|
ef2fc3ab98 | ||
|
|
5b57b05eae | ||
|
|
093579c6f5 | ||
|
|
c2d4990d7f | ||
|
|
40e8380738 | ||
|
|
b716e1e861 | ||
|
|
8432d4952c | ||
|
|
dd8f085f63 | ||
|
|
161ff8d8a3 | ||
|
|
1390cd0104 | ||
|
|
7a02b1e97f | ||
|
|
036f107c90 | ||
|
|
5652383450 | ||
|
|
9a047a5da0 | ||
|
|
8975743a37 | ||
|
|
0e30eafe49 | ||
|
|
7facb62f21 | ||
|
|
30d43cb961 | ||
|
|
c505b17e35 | ||
|
|
080c4c753d | ||
|
|
ade0d34d91 | ||
|
|
56d082eb0b | ||
|
|
795c4529ba | ||
|
|
0f5cfe22ea | ||
|
|
925ad2c3a5 | ||
|
|
f3e96907fe | ||
|
|
75a1e58a7d | ||
|
|
379e889f71 | ||
|
|
40c06f397b | ||
|
|
9e9302436e | ||
|
|
6d816d4193 | ||
|
|
438eda9c08 | ||
|
|
ace39e4633 | ||
|
|
7712391f29 | ||
|
|
65f08dcb02 | ||
|
|
1d332aa6f4 | ||
|
|
ba81641517 | ||
|
|
fb30bdb879 | ||
|
|
fc451d3b41 | ||
|
|
ffee1f3462 | ||
|
|
f30027dd13 | ||
|
|
8b6aad17f4 | ||
|
|
b77930adfb | ||
|
|
aff8f88076 | ||
|
|
4e6582e24c | ||
|
|
fa9acaccfd | ||
|
|
0414f85f12 | ||
|
|
527dd0eeb4 | ||
|
|
74ed7475c9 | ||
|
|
54dc3dba96 | ||
|
|
9980159090 | ||
|
|
0b193ebb00 | ||
|
|
f5fc9843b2 | ||
|
|
df1f67dd26 | ||
|
|
b069a5f576 | ||
|
|
7686763a03 | ||
|
|
635a6eac37 | ||
|
|
877edc535f | ||
|
|
01d59e3c1e | ||
|
|
fece2799e3 | ||
|
|
de9756ee86 | ||
|
|
51f047a51b | ||
|
|
04b66e82b7 | ||
|
|
df89253647 | ||
|
|
45dbca794e | ||
|
|
857bf28f99 | ||
|
|
e07ce15228 | ||
|
|
0637bcfd8e | ||
|
|
23db0563ac | ||
|
|
ccba71aa4e | ||
|
|
fee4bf2ad6 | ||
|
|
5052fea9ef | ||
|
|
e85215fca1 | ||
|
|
e42fe45329 | ||
|
|
4240815bd1 | ||
|
|
6f0c5305e2 | ||
|
|
757005cad8 | ||
|
|
81651ad97c | ||
|
|
f3763b6058 | ||
|
|
82478dc485 | ||
|
|
703fd05d43 | ||
|
|
ff868b6e2a | ||
|
|
051a74b37b | ||
|
|
a0a1085623 | ||
|
|
2612d3919c | ||
|
|
6f123a236f | ||
|
|
71e57e6a08 | ||
|
|
7cb18d8186 | ||
|
|
cdbf670ece | ||
|
|
e0dafee617 | ||
|
|
c37bce1563 | ||
|
|
0b3c77d644 | ||
|
|
2cf85caf86 | ||
|
|
594010ba88 | ||
|
|
d91460d2e2 | ||
|
|
89713e6ac9 | ||
|
|
17c9b2538c | ||
|
|
d337b003cb | ||
|
|
8f1485656b | ||
|
|
f0c4ec3031 | ||
|
|
458be84aca | ||
|
|
c7716aad34 | ||
|
|
4a3e734408 | ||
|
|
54cc212753 | ||
|
|
f4ae1eaa51 | ||
|
|
d2537282c9 | ||
|
|
87527688c3 | ||
|
|
2be0b6505a | ||
|
|
672f100c7c | ||
|
|
5af402c0c5 | ||
|
|
693a4f0f63 | ||
|
|
f8d2426ff6 | ||
|
|
973a9bedcd | ||
|
|
a583733400 | ||
|
|
78eb51b3ca | ||
|
|
a2606be9d8 | ||
|
|
a4975c72ce | ||
|
|
58f96822a4 | ||
|
|
96b0d94986 | ||
|
|
70b38db8c5 | ||
|
|
b6a9c2d3a0 | ||
|
|
a01df6c7db | ||
|
|
4455bee570 | ||
|
|
cd0adef2ed | ||
|
|
4aa24a65fb | ||
|
|
760dca8772 | ||
|
|
8269673619 | ||
|
|
82ec586554 | ||
|
|
ca98cc8708 | ||
|
|
f07800985d | ||
|
|
b042df93b7 | ||
|
|
ecf4441946 | ||
|
|
39b2612840 | ||
|
|
218f486e6b | ||
|
|
cfcc25f175 | ||
|
|
155e88223c | ||
|
|
05039ece51 | ||
|
|
1c673f2b46 | ||
|
|
2232a70228 | ||
|
|
e661b1d817 | ||
|
|
5a6a65f580 | ||
|
|
5cdd3bcd30 | ||
|
|
1233a885b8 | ||
|
|
adf56cd768 | ||
|
|
cd4b208be9 | ||
|
|
502de1a5d0 | ||
|
|
4158f869a3 | ||
|
|
ff569d339c | ||
|
|
10eec323dd | ||
|
|
0a3db51c7d | ||
|
|
229aee0b30 | ||
|
|
44714aa981 | ||
|
|
2b6138a889 | ||
|
|
5e424f7bf4 | ||
|
|
294e47deed | ||
|
|
dc42547b73 | ||
|
|
7ef7f0706b | ||
|
|
a59b98a7c9 | ||
|
|
088fee9a4d | ||
|
|
d8666acfe8 | ||
|
|
209e9c2866 | ||
|
|
6c3195dea4 | ||
|
|
7d774a7433 | ||
|
|
f1ec4433cf | ||
|
|
1f825db261 | ||
|
|
1019f24f1d | ||
|
|
f5c5b99579 | ||
|
|
e002d19f1b | ||
|
|
0d5c9651f0 | ||
|
|
53fc13b95c | ||
|
|
694c3b0ddc | ||
|
|
9b3d4577cc | ||
|
|
77783915dd | ||
|
|
b67ac21a79 | ||
|
|
603afed2f2 | ||
|
|
c2a7c34496 | ||
|
|
edd40f48ba | ||
|
|
cca3d6b8b9 | ||
|
|
f004512903 | ||
|
|
6407bb6730 | ||
|
|
b914eeadec | ||
|
|
dcadc6783e | ||
|
|
bc9f43634f | ||
|
|
4778f0164c | ||
|
|
9904754a07 | ||
|
|
1b79077c9e | ||
|
|
c13afb05b3 | ||
|
|
03e320efb8 | ||
|
|
7846332476 | ||
|
|
2d5d3b86e0 | ||
|
|
7c9ba890af | ||
|
|
0d609daffa | ||
|
|
c12e56d402 | ||
|
|
c7b38c07d5 | ||
|
|
dc51066cea | ||
|
|
59d2fb3010 | ||
|
|
a0fe702c10 | ||
|
|
f886f7e366 | ||
|
|
1d475d88ed | ||
|
|
e64c901912 | ||
|
|
5fce02e623 | ||
|
|
13997bc543 | ||
|
|
3e05b0d6f9 | ||
|
|
966417f867 | ||
|
|
601a0d1b91 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -29,6 +29,8 @@ target/
|
|||||||
/src/logs/
|
/src/logs/
|
||||||
*.zip
|
*.zip
|
||||||
sdkTest.log
|
sdkTest.log
|
||||||
|
app.yml
|
||||||
|
app-local.yml
|
||||||
|
|
||||||
|
|
||||||
#some local files
|
#some local files
|
||||||
|
|||||||
54
.vscode/launch.json
vendored
54
.vscode/launch.json
vendored
@@ -1,7 +1,4 @@
|
|||||||
{
|
{
|
||||||
// 使用 IntelliSense 了解相关属性。
|
|
||||||
// 悬停以查看现有属性的描述。
|
|
||||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
@@ -10,61 +7,12 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"mainClass": "${file}"
|
"mainClass": "${file}"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "java",
|
|
||||||
"name": "StringCase",
|
|
||||||
"request": "launch",
|
|
||||||
"mainClass": "cn.qaiu.vx.core.util.StringCase",
|
|
||||||
"projectName": "core"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "java",
|
|
||||||
"name": "FCURLParser",
|
|
||||||
"request": "launch",
|
|
||||||
"mainClass": "cn.qaiu.parser.FCURLParser",
|
|
||||||
"projectName": "parser"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "java",
|
|
||||||
"name": "QkTool",
|
|
||||||
"request": "launch",
|
|
||||||
"mainClass": "cn.qaiu.parser.impl.QkTool",
|
|
||||||
"projectName": "parser"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "java",
|
|
||||||
"name": "WebClientExample",
|
|
||||||
"request": "launch",
|
|
||||||
"mainClass": "qaiu.web.test.WebClientExample",
|
|
||||||
"projectName": "parser"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "java",
|
"type": "java",
|
||||||
"name": "AppMain",
|
"name": "AppMain",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"mainClass": "cn.qaiu.lz.AppMain",
|
"mainClass": "cn.qaiu.lz.AppMain",
|
||||||
"projectName": "web-service"
|
"projectName": "web-service"
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "java",
|
|
||||||
"name": "TestJs",
|
|
||||||
"request": "launch",
|
|
||||||
"mainClass": "cn.qaiu.web.test.TestJs",
|
|
||||||
"projectName": "web-service"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "java",
|
|
||||||
"name": "TestOS",
|
|
||||||
"request": "launch",
|
|
||||||
"mainClass": "cn.qaiu.web.test.TestOS",
|
|
||||||
"projectName": "web-service"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "java",
|
|
||||||
"name": "WebProxyExamples",
|
|
||||||
"request": "launch",
|
|
||||||
"mainClass": "cn.qaiu.web.test.WebProxyExamples",
|
|
||||||
"projectName": "web-service"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
|
|
||||||
# netdisk-fast-download 网盘分享链接云解析服务
|
# netdisk-fast-download 网盘分享链接云解析服务
|
||||||
QQ群:1017480890
|
QQ交流群:1017480890
|
||||||
|
|
||||||
netdisk-fast-download网盘直链云解析(nfd云解析)能把网盘分享下载链接转化为直链,支持多款云盘,已支持蓝奏云/蓝奏云优享/奶牛快传/移动云云空间/小飞机盘/亿方云/123云盘/Cloudreve等,支持加密分享,以及部分网盘文件夹分享。
|
netdisk-fast-download网盘直链云解析(nfd云解析)能把网盘分享下载链接转化为直链,支持多款云盘,已支持蓝奏云/蓝奏云优享/奶牛快传/移动云云空间/小飞机盘/亿方云/123云盘/Cloudreve等,支持加密分享,以及部分网盘文件夹分享。
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ https://nfd-parser.github.io/nfd-preview/preview.html?src=https%3A%2F%2Flz.qaiu.
|
|||||||
## 预览地址
|
## 预览地址
|
||||||
[预览地址1](https://lz.qaiu.top)
|
[预览地址1](https://lz.qaiu.top)
|
||||||
[预览地址2](https://lz0.qaiu.top)
|
[预览地址2](https://lz0.qaiu.top)
|
||||||
[移动/联通/天翼云盘大文件试用版](https://189.qaiu.top)
|
[天翼云盘/移动云盘限时体验版](https://189.qaiu.top)
|
||||||
|
|
||||||
main分支依赖JDK17, 提供了JDK11分支[main-jdk11](https://github.com/qaiu/netdisk-fast-download/tree/main-jdk11)
|
main分支依赖JDK17, 提供了JDK11分支[main-jdk11](https://github.com/qaiu/netdisk-fast-download/tree/main-jdk11)
|
||||||
**0.1.8及以上版本json接口格式有调整 参考json返回数据格式示例**
|
**0.1.8及以上版本json接口格式有调整 参考json返回数据格式示例**
|
||||||
@@ -94,6 +94,8 @@ main分支依赖JDK17, 提供了JDK11分支[main-jdk11](https://github.com/qaiu/
|
|||||||
- [天翼云盘-p189](https://cloud.189.cn/)
|
- [天翼云盘-p189](https://cloud.189.cn/)
|
||||||
|
|
||||||
## API接口
|
## API接口
|
||||||
|
|
||||||
|
[api接口文档](https://nfdparser.apifox.cn/)
|
||||||
|
|
||||||
### 服务端口
|
### 服务端口
|
||||||
- **6400**: API 服务端口(建议使用 Nginx 代理)
|
- **6400**: API 服务端口(建议使用 Nginx 代理)
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ public enum PanDomainTemplate {
|
|||||||
"lanzoug|" +
|
"lanzoug|" +
|
||||||
"lanzoum" +
|
"lanzoum" +
|
||||||
")\\.com/(.+/)?(?<KEY>.+)"),
|
")\\.com/(.+/)?(?<KEY>.+)"),
|
||||||
"https://lanzoux.com/{shareKey}",
|
"https://w1.lanzn.com/{shareKey}",
|
||||||
LzTool.class),
|
LzTool.class),
|
||||||
|
|
||||||
// https://www.feijix.com/s/
|
// https://www.feijix.com/s/
|
||||||
|
|||||||
@@ -244,19 +244,17 @@ public class JsHttpClient {
|
|||||||
|
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
if (data instanceof String) {
|
if (data instanceof String) {
|
||||||
request.sendBuffer(Buffer.buffer((String) data));
|
return request.sendBuffer(Buffer.buffer((String) data));
|
||||||
} else if (data instanceof Map) {
|
} else if (data instanceof Map) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, String> mapData = (Map<String, String>) data;
|
Map<String, String> mapData = (Map<String, String>) data;
|
||||||
request.sendForm(MultiMap.caseInsensitiveMultiMap().addAll(mapData));
|
return request.sendForm(MultiMap.caseInsensitiveMultiMap().addAll(mapData));
|
||||||
} else {
|
} else {
|
||||||
request.sendJson(data);
|
return request.sendJson(data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
request.send();
|
return request.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
return request.send();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,19 +274,17 @@ public class JsHttpClient {
|
|||||||
|
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
if (data instanceof String) {
|
if (data instanceof String) {
|
||||||
request.sendBuffer(Buffer.buffer((String) data));
|
return request.sendBuffer(Buffer.buffer((String) data));
|
||||||
} else if (data instanceof Map) {
|
} else if (data instanceof Map) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, String> mapData = (Map<String, String>) data;
|
Map<String, String> mapData = (Map<String, String>) data;
|
||||||
request.sendForm(MultiMap.caseInsensitiveMultiMap().addAll(mapData));
|
return request.sendForm(MultiMap.caseInsensitiveMultiMap().addAll(mapData));
|
||||||
} else {
|
} else {
|
||||||
request.sendJson(data);
|
return request.sendJson(data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
request.send();
|
return request.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
return request.send();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,19 +318,17 @@ public class JsHttpClient {
|
|||||||
|
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
if (data instanceof String) {
|
if (data instanceof String) {
|
||||||
request.sendBuffer(Buffer.buffer((String) data));
|
return request.sendBuffer(Buffer.buffer((String) data));
|
||||||
} else if (data instanceof Map) {
|
} else if (data instanceof Map) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, String> mapData = (Map<String, String>) data;
|
Map<String, String> mapData = (Map<String, String>) data;
|
||||||
request.sendForm(MultiMap.caseInsensitiveMultiMap().addAll(mapData));
|
return request.sendForm(MultiMap.caseInsensitiveMultiMap().addAll(mapData));
|
||||||
} else {
|
} else {
|
||||||
request.sendJson(data);
|
return request.sendJson(data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
request.send();
|
return request.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
return request.send();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ public class JsPlaygroundExecutor {
|
|||||||
playgroundLogger.infoJava("✅ Fetch API和Promise polyfill注入成功");
|
playgroundLogger.infoJava("✅ Fetch API和Promise polyfill注入成功");
|
||||||
}
|
}
|
||||||
|
|
||||||
playgroundLogger.infoJava("🔒 安全的JavaScript引擎初始化成功(演练场)");
|
playgroundLogger.infoJava("初始化成功");
|
||||||
|
|
||||||
// 执行JavaScript代码
|
// 执行JavaScript代码
|
||||||
engine.eval(jsCode);
|
engine.eval(jsCode);
|
||||||
|
|||||||
@@ -1,30 +1,72 @@
|
|||||||
package cn.qaiu.parser.impl;
|
package cn.qaiu.parser.impl;
|
||||||
|
|
||||||
|
import cn.qaiu.entity.FileInfo;
|
||||||
import cn.qaiu.entity.ShareLinkInfo;
|
import cn.qaiu.entity.ShareLinkInfo;
|
||||||
import cn.qaiu.parser.PanBase;
|
import cn.qaiu.parser.PanBase;
|
||||||
|
import cn.qaiu.util.FileSizeConverter;
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
|
import io.vertx.core.MultiMap;
|
||||||
|
import io.vertx.core.Promise;
|
||||||
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 java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <a href="https://lecloud.lenovo.com/">联想乐云</a>
|
* <a href="https://lecloud.lenovo.com/">联想乐云</a>
|
||||||
*/
|
*/
|
||||||
public class LeTool extends PanBase {
|
public class LeTool extends PanBase {
|
||||||
private static final String API_URL_PREFIX = "https://lecloud.lenovo.com/share/api/clouddiskapi/share/public/v1/";
|
private static final String API_URL_PREFIX = "https://lecloud.lenovo.com/mshare/api/clouddiskapi/share/public/v1/";
|
||||||
|
private static final String DEFAULT_FILE_TYPE = "file";
|
||||||
|
private static final int FILE_TYPE_DIRECTORY = 0; // 目录类型
|
||||||
|
|
||||||
|
private static final MultiMap HEADERS;
|
||||||
|
|
||||||
|
static {
|
||||||
|
HEADERS = MultiMap.caseInsensitiveMultiMap();
|
||||||
|
HEADERS.set("Accept", "application/json, text/plain, */*");
|
||||||
|
HEADERS.set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");
|
||||||
|
HEADERS.set("Cache-Control", "no-cache");
|
||||||
|
HEADERS.set("Connection", "keep-alive");
|
||||||
|
HEADERS.set("Content-Type", "application/json");
|
||||||
|
HEADERS.set("DNT", "1");
|
||||||
|
HEADERS.set("Origin", "https://lecloud.lenovo.com");
|
||||||
|
HEADERS.set("Pragma", "no-cache");
|
||||||
|
HEADERS.set("Sec-Fetch-Dest", "empty");
|
||||||
|
HEADERS.set("Sec-Fetch-Mode", "cors");
|
||||||
|
HEADERS.set("Sec-Fetch-Site", "same-origin");
|
||||||
|
HEADERS.set("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1 Edg/143.0.0.0");
|
||||||
|
}
|
||||||
|
|
||||||
public LeTool(ShareLinkInfo shareLinkInfo) {
|
public LeTool(ShareLinkInfo shareLinkInfo) {
|
||||||
super(shareLinkInfo);
|
super(shareLinkInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取干净的 shareId(去掉可能的查询参数)
|
||||||
|
* URL 如 https://lecloud.lenovo.com/share/5eoN3RA5PLhQcH4zE?path=... 会导致 shareKey 包含查询参数
|
||||||
|
*/
|
||||||
|
private String getCleanShareId() {
|
||||||
|
String shareKey = shareLinkInfo.getShareKey();
|
||||||
|
if (shareKey != null && shareKey.contains("?")) {
|
||||||
|
return shareKey.split("\\?")[0];
|
||||||
|
}
|
||||||
|
return shareKey;
|
||||||
|
}
|
||||||
|
|
||||||
public Future<String> parse() {
|
public Future<String> parse() {
|
||||||
final String dataKey = shareLinkInfo.getShareKey();
|
final String dataKey = getCleanShareId();
|
||||||
final String pwd = shareLinkInfo.getSharePassword();
|
final String pwd = shareLinkInfo.getSharePassword();
|
||||||
// {"shareId":"xxx","password":"xxx","directoryId":"-1"}
|
// {"shareId":"xxx","password":"xxx","directoryId":"-1"}
|
||||||
String apiUrl1 = API_URL_PREFIX + "shareInfo";
|
String apiUrl1 = API_URL_PREFIX + "shareInfo";
|
||||||
client.postAbs(apiUrl1)
|
client.postAbs(apiUrl1)
|
||||||
.sendJsonObject(JsonObject.of("shareId", dataKey, "password", pwd, "directoryId", -1))
|
.putHeaders(HEADERS)
|
||||||
|
.sendJsonObject(JsonObject.of("shareId", dataKey, "password", pwd, "directoryId", "-1"))
|
||||||
.onSuccess(res -> {
|
.onSuccess(res -> {
|
||||||
JsonObject resJson = asJson(res);
|
JsonObject resJson = asJson(res);
|
||||||
if (resJson.containsKey("result")) {
|
if (resJson.containsKey("result")) {
|
||||||
@@ -44,7 +86,19 @@ public class LeTool extends PanBase {
|
|||||||
}
|
}
|
||||||
JsonObject fileInfoJson = files.getJsonObject(0);
|
JsonObject fileInfoJson = files.getJsonObject(0);
|
||||||
if (fileInfoJson != null) {
|
if (fileInfoJson != null) {
|
||||||
// TODO 文件大小fileSize和文件名fileName
|
// Extract and populate FileInfo
|
||||||
|
FileInfo fileInfo = createFileInfo(fileInfoJson);
|
||||||
|
shareLinkInfo.getOtherParam().put("fileInfo", fileInfo);
|
||||||
|
|
||||||
|
// 判断是否为目录
|
||||||
|
Integer fileType = fileInfoJson.getInteger("fileType");
|
||||||
|
if (fileType != null && fileType == FILE_TYPE_DIRECTORY) {
|
||||||
|
// 如果是目录,返回目录ID
|
||||||
|
String fileId = fileInfoJson.getString("fileId");
|
||||||
|
promise.complete(fileId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String fileId = fileInfoJson.getString("fileId");
|
String fileId = fileInfoJson.getString("fileId");
|
||||||
// 根据文件ID获取跳转链接
|
// 根据文件ID获取跳转链接
|
||||||
getDownURL(dataKey, fileId);
|
getDownURL(dataKey, fileId);
|
||||||
@@ -59,13 +113,205 @@ public class LeTool extends PanBase {
|
|||||||
return promise.future();
|
return promise.future();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Future<List<FileInfo>> parseFileList() {
|
||||||
|
Promise<List<FileInfo>> listPromise = Promise.promise();
|
||||||
|
|
||||||
|
String dataKey = getCleanShareId();
|
||||||
|
|
||||||
|
// 如果参数里的目录ID不为空,则直接解析目录
|
||||||
|
String dirId = (String) shareLinkInfo.getOtherParam().get("dirId");
|
||||||
|
if (dirId == null || dirId.isEmpty()) {
|
||||||
|
// 如果没有指定目录ID,使用根目录ID "-1"
|
||||||
|
dirId = "-1";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 直接请求shareInfo接口解析目录
|
||||||
|
parseDirectory(dirId, dataKey, listPromise);
|
||||||
|
return listPromise.future();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析目录下的文件列表
|
||||||
|
*/
|
||||||
|
private void parseDirectory(String directoryId, String shareId, Promise<List<FileInfo>> promise) {
|
||||||
|
String pwd = shareLinkInfo.getSharePassword();
|
||||||
|
if (pwd == null) {
|
||||||
|
pwd = "";
|
||||||
|
}
|
||||||
|
String apiUrl = API_URL_PREFIX + "shareInfo";
|
||||||
|
|
||||||
|
JsonObject requestBody = JsonObject.of("shareId", shareId, "password", pwd, "directoryId", directoryId);
|
||||||
|
log.info("解析目录请求: url={}, body={}", apiUrl, requestBody.encode());
|
||||||
|
|
||||||
|
client.postAbs(apiUrl)
|
||||||
|
.putHeaders(HEADERS)
|
||||||
|
.sendJsonObject(requestBody)
|
||||||
|
.onSuccess(res -> {
|
||||||
|
JsonObject resJson = asJson(res);
|
||||||
|
|
||||||
|
if (!resJson.containsKey("result") || !resJson.getBoolean("result")) {
|
||||||
|
promise.fail("解析目录失败: " + resJson.encode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject dataJson = resJson.getJsonObject("data");
|
||||||
|
if (!dataJson.getBoolean("passwordVerified")) {
|
||||||
|
promise.fail("密码验证失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonArray files = dataJson.getJsonArray("files");
|
||||||
|
if (files == null || files.isEmpty()) {
|
||||||
|
promise.complete(new ArrayList<>());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<FileInfo> fileList = new ArrayList<>();
|
||||||
|
for (int i = 0; i < files.size(); i++) {
|
||||||
|
JsonObject fileJson = files.getJsonObject(i);
|
||||||
|
FileInfo fileInfo = createFileInfoForList(fileJson, shareId);
|
||||||
|
fileList.add(fileInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
promise.complete(fileList);
|
||||||
|
})
|
||||||
|
.onFailure(err -> {
|
||||||
|
log.error("解析目录请求失败: {}", err.getMessage());
|
||||||
|
promise.fail(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为文件列表创建 FileInfo 对象
|
||||||
|
*/
|
||||||
|
private FileInfo createFileInfoForList(JsonObject fileJson, String shareId) {
|
||||||
|
FileInfo fileInfo = new FileInfo();
|
||||||
|
|
||||||
|
try {
|
||||||
|
String fileId = fileJson.getString("fileId");
|
||||||
|
String fileName = fileJson.getString("fileName");
|
||||||
|
Long fileSize = fileJson.getLong("fileSize");
|
||||||
|
Integer fileType = fileJson.getInteger("fileType");
|
||||||
|
|
||||||
|
fileInfo.setFileId(fileId);
|
||||||
|
fileInfo.setFileName(fileName);
|
||||||
|
fileInfo.setPanType(shareLinkInfo.getType());
|
||||||
|
|
||||||
|
// 判断是否为目录
|
||||||
|
if (fileType != null && fileType == FILE_TYPE_DIRECTORY) {
|
||||||
|
// 目录类型
|
||||||
|
fileInfo.setFileType("folder");
|
||||||
|
fileInfo.setSize(0L);
|
||||||
|
fileInfo.setSizeStr("0B");
|
||||||
|
// 设置目录解析的URL - fileId 需要进行 URL 编码以保持特殊字符的编码状态
|
||||||
|
try {
|
||||||
|
String encodedFileId = URLEncoder.encode(fileId, "UTF-8");
|
||||||
|
fileInfo.setParserUrl(String.format("%s/v2/getFileList?url=%s&dirId=%s",
|
||||||
|
getDomainName(),
|
||||||
|
shareLinkInfo.getShareUrl(),
|
||||||
|
encodedFileId));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
log.error("URL编码失败: {}", e.getMessage());
|
||||||
|
// 降级方案:直接使用原始 fileId
|
||||||
|
fileInfo.setParserUrl(String.format("%s/v2/getFileList?url=%s&dirId=%s",
|
||||||
|
getDomainName(),
|
||||||
|
shareLinkInfo.getShareUrl(),
|
||||||
|
fileId));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 文件类型
|
||||||
|
fileInfo.setFileType(fileType != null ? String.valueOf(fileType) : DEFAULT_FILE_TYPE);
|
||||||
|
fileInfo.setSize(fileSize);
|
||||||
|
fileInfo.setSizeStr(FileSizeConverter.convertToReadableSize(fileSize));
|
||||||
|
|
||||||
|
// 创建参数JSON并编码为Base64
|
||||||
|
JsonObject paramJson = JsonObject.of(
|
||||||
|
"shareId", shareId,
|
||||||
|
"fileId", fileId
|
||||||
|
);
|
||||||
|
String paramBase64 = Base64.getEncoder().encodeToString(paramJson.encode().getBytes());
|
||||||
|
|
||||||
|
// 设置解析URL和预览URL
|
||||||
|
fileInfo.setParserUrl(String.format("%s/v2/redirectUrl/%s/%s",
|
||||||
|
getDomainName(),
|
||||||
|
shareLinkInfo.getType(),
|
||||||
|
paramBase64))
|
||||||
|
.setPreviewUrl(String.format("%s/v2/viewUrl/%s/%s",
|
||||||
|
getDomainName(),
|
||||||
|
shareLinkInfo.getType(),
|
||||||
|
paramBase64));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("创建文件信息失败: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Future<String> parseById() {
|
||||||
|
Promise<String> parsePromise = Promise.promise();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 从参数中获取解析所需的信息
|
||||||
|
JsonObject paramJson = (JsonObject) shareLinkInfo.getOtherParam().get("paramJson");
|
||||||
|
String shareId = paramJson.getString("shareId");
|
||||||
|
String fileId = paramJson.getString("fileId");
|
||||||
|
|
||||||
|
// 调用获取下载链接
|
||||||
|
getDownURLForById(shareId, fileId, parsePromise);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
parsePromise.fail("解析参数失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsePromise.future();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据文件ID获取下载URL (用于 parseById)
|
||||||
|
*/
|
||||||
|
private void getDownURLForById(String shareId, String fileId, Promise<String> promise) {
|
||||||
|
String uuid = UUID.randomUUID().toString();
|
||||||
|
JsonArray fileIds = JsonArray.of(fileId);
|
||||||
|
String apiUrl = API_URL_PREFIX + "packageDownloadWithFileIds";
|
||||||
|
|
||||||
|
client.postAbs(apiUrl)
|
||||||
|
.putHeaders(HEADERS)
|
||||||
|
.sendJsonObject(JsonObject.of("fileIds", fileIds, "shareId", shareId, "browserId", uuid))
|
||||||
|
.onSuccess(res -> {
|
||||||
|
JsonObject resJson = asJson(res);
|
||||||
|
if (resJson.containsKey("result")) {
|
||||||
|
if (resJson.getBoolean("result")) {
|
||||||
|
JsonObject dataJson = resJson.getJsonObject("data");
|
||||||
|
String downloadUrl = dataJson.getString("downloadUrl");
|
||||||
|
if (downloadUrl == null) {
|
||||||
|
promise.fail("Result JSON数据异常: downloadUrl不存在");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 获取重定向链接
|
||||||
|
clientNoRedirects.getAbs(downloadUrl).send()
|
||||||
|
.onSuccess(res2 -> promise.complete(res2.headers().get("Location")))
|
||||||
|
.onFailure(err -> promise.fail(err));
|
||||||
|
} else {
|
||||||
|
promise.fail(resJson.getString("errcode") + ": " + resJson.getString("errmsg"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
promise.fail("Result JSON数据异常: result字段不存在");
|
||||||
|
}
|
||||||
|
}).onFailure(err -> promise.fail(err));
|
||||||
|
}
|
||||||
|
|
||||||
private void getDownURL(String key, String fileId) {
|
private void getDownURL(String key, String fileId) {
|
||||||
String uuid = UUID.randomUUID().toString();
|
String uuid = UUID.randomUUID().toString();
|
||||||
JsonArray fileIds = JsonArray.of(fileId);
|
JsonArray fileIds = JsonArray.of(fileId);
|
||||||
String apiUrl2 = API_URL_PREFIX + "packageDownloadWithFileIds";
|
String apiUrl2 = API_URL_PREFIX + "packageDownloadWithFileIds";
|
||||||
// {"fileIds":[123],"shareId":"xxx","browserId":"uuid"}
|
// {"fileIds":[123],"shareId":"xxx","browserId":"uuid"}
|
||||||
client.postAbs(apiUrl2)
|
client.postAbs(apiUrl2)
|
||||||
.sendJsonObject(JsonObject.of("fileIds", fileIds, "shareId", key, "browserId", uuid))
|
.putHeaders(HEADERS)
|
||||||
|
.sendJsonObject(JsonObject.of("fileIds", fileIds, "shareId", key, "browserId", uuid))
|
||||||
.onSuccess(res -> {
|
.onSuccess(res -> {
|
||||||
JsonObject resJson = asJson(res);
|
JsonObject resJson = asJson(res);
|
||||||
if (resJson.containsKey("result")) {
|
if (resJson.containsKey("result")) {
|
||||||
@@ -89,4 +335,51 @@ public class LeTool extends PanBase {
|
|||||||
}
|
}
|
||||||
}).onFailure(handleFail(apiUrl2));
|
}).onFailure(handleFail(apiUrl2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create FileInfo object from JSON response
|
||||||
|
* Uses exact field names from the API response without fallback checks
|
||||||
|
*/
|
||||||
|
private FileInfo createFileInfo(JsonObject fileInfoJson) {
|
||||||
|
FileInfo fileInfo = new FileInfo();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Set fileId
|
||||||
|
String fileId = fileInfoJson.getString("fileId");
|
||||||
|
if (fileId != null) {
|
||||||
|
fileInfo.setFileId(fileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set fileName
|
||||||
|
String fileName = fileInfoJson.getString("fileName");
|
||||||
|
if (fileName != null) {
|
||||||
|
fileInfo.setFileName(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set file size
|
||||||
|
Long fileSize = fileInfoJson.getLong("fileSize");
|
||||||
|
if (fileSize != null) {
|
||||||
|
fileInfo.setSize(fileSize);
|
||||||
|
// Convert to readable size string
|
||||||
|
fileInfo.setSizeStr(FileSizeConverter.convertToReadableSize(fileSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set fileType (API returns it as an integer)
|
||||||
|
Integer fileTypeInt = fileInfoJson.getInteger("fileType");
|
||||||
|
if (fileTypeInt != null) {
|
||||||
|
fileInfo.setFileType(String.valueOf(fileTypeInt));
|
||||||
|
} else {
|
||||||
|
// Default to generic file type if not available
|
||||||
|
fileInfo.setFileType(DEFAULT_FILE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set panType
|
||||||
|
fileInfo.setPanType(shareLinkInfo.getType());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Error extracting file info from JSON: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,14 +11,12 @@ 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.WebClientSession;
|
import io.vertx.ext.web.client.WebClientSession;
|
||||||
import org.apache.commons.lang3.RegExUtils;
|
|
||||||
import org.openjdk.nashorn.api.scripting.ScriptObjectMirror;
|
import org.openjdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||||
|
|
||||||
import javax.script.ScriptException;
|
import javax.script.ScriptException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@@ -29,13 +27,14 @@ import java.util.regex.Pattern;
|
|||||||
*/
|
*/
|
||||||
public class LzTool extends PanBase {
|
public class LzTool extends PanBase {
|
||||||
|
|
||||||
public static final String SHARE_URL_PREFIX = "https://wwwwp.lanzoup.com";
|
WebClientSession webClientSession = WebClientSession.create(clientNoRedirects);
|
||||||
|
|
||||||
|
public static final String SHARE_URL_PREFIX = "https://w1.lanzn.com/";
|
||||||
MultiMap headers0 = HeaderUtils.parseHeaders("""
|
MultiMap headers0 = HeaderUtils.parseHeaders("""
|
||||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
|
||||||
Accept-Encoding: gzip, deflate
|
Accept-Encoding: gzip, deflate
|
||||||
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
|
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
|
||||||
Cache-Control: max-age=0
|
Cache-Control: max-age=0
|
||||||
Cookie: codelen=1; pc_ad1=1
|
|
||||||
DNT: 1
|
DNT: 1
|
||||||
Priority: u=0, i
|
Priority: u=0, i
|
||||||
Sec-CH-UA: "Chromium";v="140", "Not=A?Brand";v="24", "Microsoft Edge";v="140"
|
Sec-CH-UA: "Chromium";v="140", "Not=A?Brand";v="24", "Microsoft Edge";v="140"
|
||||||
@@ -63,53 +62,100 @@ public class LzTool extends PanBase {
|
|||||||
.putHeaders(headers0)
|
.putHeaders(headers0)
|
||||||
.send().onSuccess(res -> {
|
.send().onSuccess(res -> {
|
||||||
String html = asText(res);
|
String html = asText(res);
|
||||||
try {
|
if (html.contains("var arg1='")) {
|
||||||
setFileInfo(html, shareLinkInfo);
|
webClientSession = WebClientSession.create(clientNoRedirects);
|
||||||
} catch (Exception e) {
|
setCookie(html);
|
||||||
e.printStackTrace();
|
webClientSession.getAbs(sUrl)
|
||||||
}
|
.putHeaders(headers0)
|
||||||
// 匹配iframe
|
.send().onSuccess(res2 -> {
|
||||||
Pattern compile = Pattern.compile("src=\"(/fn\\?[a-zA-Z\\d_+/=]{16,})\"");
|
String html2 = asText(res2);
|
||||||
Matcher matcher = compile.matcher(html);
|
doParser(html2, pwd, sUrl);
|
||||||
// 没有Iframe说明是加密分享, 匹配sign通过密码请求下载页面
|
});
|
||||||
if (!matcher.find()) {
|
|
||||||
try {
|
|
||||||
String jsText = getJsByPwd(pwd, html, "document.getElementById('rpt')");
|
|
||||||
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText, "down_p");
|
|
||||||
getDownURL(sUrl, client, scriptObjectMirror);
|
|
||||||
} catch (Exception e) {
|
|
||||||
fail(e, "js引擎执行失败");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 没有密码
|
|
||||||
String iframePath = matcher.group(1);
|
|
||||||
client.getAbs(SHARE_URL_PREFIX + iframePath).send().onSuccess(res2 -> {
|
|
||||||
String html2 = res2.bodyAsString();
|
|
||||||
|
|
||||||
// 去TMD正则
|
} else {
|
||||||
// Matcher matcher2 = Pattern.compile("'sign'\s*:\s*'(\\w+)'").matcher(html2);
|
doParser(html, pwd, sUrl);
|
||||||
String jsText = getJsText(html2);
|
|
||||||
if (jsText == null) {
|
|
||||||
fail(SHARE_URL_PREFIX + iframePath + " -> " + sUrl + ": js脚本匹配失败, 可能分享已失效");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText, null);
|
|
||||||
getDownURL(sUrl, client, scriptObjectMirror);
|
|
||||||
} catch (ScriptException | NoSuchMethodException e) {
|
|
||||||
fail(e, "js引擎执行失败");
|
|
||||||
}
|
|
||||||
}).onFailure(handleFail(SHARE_URL_PREFIX));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}).onFailure(handleFail(sUrl));
|
}).onFailure(handleFail(sUrl));
|
||||||
return promise.future();
|
return promise.future();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void doParser(String html, String pwd, String sUrl) {
|
||||||
|
try {
|
||||||
|
setFileInfo(html, shareLinkInfo);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
// 匹配iframe
|
||||||
|
Pattern compile = Pattern.compile("src=\"(/fn\\?[a-zA-Z\\d_+/=]{16,})\"");
|
||||||
|
Matcher matcher = compile.matcher(html);
|
||||||
|
// 没有Iframe说明是加密分享, 匹配sign通过密码请求下载页面
|
||||||
|
if (!matcher.find()) {
|
||||||
|
try {
|
||||||
|
String jsText = getJsByPwd(pwd, html, "document.getElementById('rpt')");
|
||||||
|
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText, "down_p");
|
||||||
|
getDownURL(sUrl, scriptObjectMirror);
|
||||||
|
} catch (Exception e) {
|
||||||
|
fail(e, "js引擎执行失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 没有密码
|
||||||
|
String iframePath = matcher.group(1);
|
||||||
|
String absoluteURI = SHARE_URL_PREFIX + iframePath;
|
||||||
|
webClientSession.getAbs(absoluteURI).putHeaders(headers0).send().onSuccess(res2 -> {
|
||||||
|
String html2= asText(res2);
|
||||||
|
// Matcher matcher2 = Pattern.compile("'sign'\s*:\s*'(\\w+)'").matcher(html2);
|
||||||
|
String jsText = getJsText(html2);
|
||||||
|
if (jsText == null) {
|
||||||
|
headers0.add("Referer", absoluteURI);
|
||||||
|
setCookie(html2);
|
||||||
|
webClientSession.getAbs(absoluteURI).send().onSuccess(res3 -> {
|
||||||
|
String html3= asText(res3);
|
||||||
|
String jsText3 = getJsText(html3);
|
||||||
|
if (jsText3 != null) {
|
||||||
|
try {
|
||||||
|
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText3, null);
|
||||||
|
getDownURL(sUrl, scriptObjectMirror);
|
||||||
|
} catch (ScriptException | NoSuchMethodException e) {
|
||||||
|
fail(e, "引擎执行失败");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
fail(SHARE_URL_PREFIX + iframePath + " -> " + sUrl + ": 获取失败0, 可能分享已失效");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText, null);
|
||||||
|
getDownURL(sUrl, scriptObjectMirror);
|
||||||
|
} catch (ScriptException | NoSuchMethodException e) {
|
||||||
|
fail(e, "js引擎执行失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).onFailure(handleFail(SHARE_URL_PREFIX));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setCookie(String html2) {
|
||||||
|
int beginIndex = html2.indexOf("arg1='") + 6;
|
||||||
|
String arg1 = html2.substring(beginIndex, html2.indexOf("';", beginIndex));
|
||||||
|
String acw_sc__v2 = AcwScV2Generator.acwScV2Simple(arg1);
|
||||||
|
// 创建一个 Cookie 并放入 CookieStore
|
||||||
|
DefaultCookie nettyCookie = new DefaultCookie("acw_sc__v2", acw_sc__v2);
|
||||||
|
nettyCookie.setDomain(".lanzn.com"); // 设置域名
|
||||||
|
nettyCookie.setPath("/"); // 设置路径
|
||||||
|
nettyCookie.setSecure(false);
|
||||||
|
nettyCookie.setHttpOnly(false);
|
||||||
|
webClientSession.cookieStore().put(nettyCookie);
|
||||||
|
}
|
||||||
|
|
||||||
private String getJsByPwd(String pwd, String html, String subText) {
|
private String getJsByPwd(String pwd, String html, String subText) {
|
||||||
String jsText = getJsText(html);
|
String jsText = getJsText(html);
|
||||||
|
|
||||||
if (jsText == null) {
|
if (jsText == null) {
|
||||||
throw new RuntimeException("js脚本匹配失败, 可能分享已失效");
|
throw new RuntimeException("获取失败1, 可能分享已失效");
|
||||||
}
|
}
|
||||||
jsText = jsText.replace("document.getElementById('pwd').value", "\"" + pwd + "\"");
|
jsText = jsText.replace("document.getElementById('pwd').value", "\"" + pwd + "\"");
|
||||||
int i = jsText.indexOf(subText);
|
int i = jsText.indexOf(subText);
|
||||||
@@ -131,7 +177,7 @@ public class LzTool extends PanBase {
|
|||||||
return html.substring(startPos, endPos).replaceAll("<!--.*-->", "");
|
return html.substring(startPos, endPos).replaceAll("<!--.*-->", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getDownURL(String key, WebClient client, Map<String, ?> obj) {
|
private void getDownURL(String key, Map<String, ?> obj) {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
fail("需要访问密码");
|
fail("需要访问密码");
|
||||||
return;
|
return;
|
||||||
@@ -163,7 +209,7 @@ public class LzTool extends PanBase {
|
|||||||
headers.set("referer", key);
|
headers.set("referer", key);
|
||||||
// action=downprocess&signs=%3Fctdf&websignkey=I5gl&sign=BWMGOF1sBTRWXwI9BjZdYVA7BDhfNAIyUG9UawJtUGMIPlAhACkCa1UyUTAAYFxvUj5XY1E7UGFXaFVq&websign=&kd=1&ves=1
|
// action=downprocess&signs=%3Fctdf&websignkey=I5gl&sign=BWMGOF1sBTRWXwI9BjZdYVA7BDhfNAIyUG9UawJtUGMIPlAhACkCa1UyUTAAYFxvUj5XY1E7UGFXaFVq&websign=&kd=1&ves=1
|
||||||
String url = SHARE_URL_PREFIX + url0;
|
String url = SHARE_URL_PREFIX + url0;
|
||||||
client.postAbs(url).putHeaders(headers).sendForm(map).onSuccess(res2 -> {
|
webClientSession.postAbs(url).putHeaders(headers).sendForm(map).onSuccess(res2 -> {
|
||||||
try {
|
try {
|
||||||
JsonObject urlJson = asJson(res2);
|
JsonObject urlJson = asJson(res2);
|
||||||
String name = urlJson.getString("inf");
|
String name = urlJson.getString("inf");
|
||||||
@@ -178,7 +224,6 @@ public class LzTool extends PanBase {
|
|||||||
|
|
||||||
String downUrl = urlJson.getString("dom") + "/file/" + urlJson.getString("url");
|
String downUrl = urlJson.getString("dom") + "/file/" + urlJson.getString("url");
|
||||||
headers.remove("Referer");
|
headers.remove("Referer");
|
||||||
WebClientSession webClientSession = WebClientSession.create(client);
|
|
||||||
webClientSession.getAbs(downUrl).putHeaders(headers).send()
|
webClientSession.getAbs(downUrl).putHeaders(headers).send()
|
||||||
.onSuccess(res3 -> {
|
.onSuccess(res3 -> {
|
||||||
String location = res3.headers().get("Location");
|
String location = res3.headers().get("Location");
|
||||||
@@ -195,12 +240,13 @@ public class LzTool extends PanBase {
|
|||||||
nettyCookie.setPath("/"); // 设置路径
|
nettyCookie.setPath("/"); // 设置路径
|
||||||
nettyCookie.setSecure(false);
|
nettyCookie.setSecure(false);
|
||||||
nettyCookie.setHttpOnly(false);
|
nettyCookie.setHttpOnly(false);
|
||||||
webClientSession.cookieStore().put(nettyCookie);
|
WebClientSession webClientSession2 = WebClientSession.create(clientNoRedirects);
|
||||||
webClientSession.getAbs(downUrl).putHeaders(headers).send()
|
webClientSession2.cookieStore().put(nettyCookie);
|
||||||
|
webClientSession2.getAbs(downUrl).putHeaders(headers).send()
|
||||||
.onSuccess(res4 -> {
|
.onSuccess(res4 -> {
|
||||||
String location0 = res4.headers().get("Location");
|
String location0 = res4.headers().get("Location");
|
||||||
if (location0 == null) {
|
if (location0 == null) {
|
||||||
fail(downUrl + " -> 直链获取失败, 可能分享已失效");
|
fail(downUrl + " -> 直链获取失败2, 可能分享已失效");
|
||||||
} else {
|
} else {
|
||||||
setDateAndComplate(location0);
|
setDateAndComplate(location0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -549,6 +549,176 @@ public class JsHttpClientTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPostWithJsonString() {
|
||||||
|
System.out.println("\n[测试16] POST请求(JSON字符串) - httpbin.org/post");
|
||||||
|
System.out.println("测试修复:POST请求发送JSON字符串时请求体是否正确发送");
|
||||||
|
|
||||||
|
try {
|
||||||
|
String url = "https://httpbin.org/post";
|
||||||
|
System.out.println("请求URL: " + url);
|
||||||
|
|
||||||
|
// 模拟阿里云盘登录请求格式
|
||||||
|
String jsonData = "{\"grant_type\":\"refresh_token\",\"refresh_token\":\"test_token_123\"}";
|
||||||
|
System.out.println("POST数据(JSON字符串): " + jsonData);
|
||||||
|
|
||||||
|
// 设置Content-Type为application/json
|
||||||
|
httpClient.putHeader("Content-Type", "application/json");
|
||||||
|
System.out.println("设置Content-Type: application/json");
|
||||||
|
System.out.println("开始请求...");
|
||||||
|
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
JsHttpClient.JsHttpResponse response = httpClient.post(url, jsonData);
|
||||||
|
long endTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
System.out.println("请求完成,耗时: " + (endTime - startTime) + "ms");
|
||||||
|
System.out.println("状态码: " + response.statusCode());
|
||||||
|
|
||||||
|
String body = response.body();
|
||||||
|
System.out.println("响应体(前500字符): " + (body != null && body.length() > 500 ? body.substring(0, 500) + "..." : body));
|
||||||
|
|
||||||
|
// 验证结果
|
||||||
|
assertNotNull("响应不能为null", response);
|
||||||
|
assertEquals("状态码应该是200", 200, response.statusCode());
|
||||||
|
assertNotNull("响应体不能为null", body);
|
||||||
|
// 验证请求体是否正确发送(httpbin会回显请求数据)
|
||||||
|
assertTrue("响应体应该包含发送的JSON数据",
|
||||||
|
body.contains("grant_type") || body.contains("refresh_token"));
|
||||||
|
|
||||||
|
System.out.println("✓ 测试通过 - POST请求体已正确发送");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("✗ 测试失败: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
fail("POST JSON字符串请求测试失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAlipanTokenApi() {
|
||||||
|
System.out.println("\n[测试20] 阿里云盘Token接口测试 - auth.aliyundrive.com/v2/account/token");
|
||||||
|
System.out.println("参考 alipan.js 中的登录逻辑,测试请求格式是否正确");
|
||||||
|
|
||||||
|
try {
|
||||||
|
String tokenUrl = "https://auth.aliyundrive.com/v2/account/token";
|
||||||
|
System.out.println("请求URL: " + tokenUrl);
|
||||||
|
|
||||||
|
// 参考 alipan.js 中的请求格式
|
||||||
|
// setJsonHeaders(http) 设置 Content-Type: application/json 和 User-Agent
|
||||||
|
httpClient.putHeader("Content-Type", "application/json");
|
||||||
|
httpClient.putHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||||
|
|
||||||
|
// 参考 alipan.js: JSON.stringify({grant_type: "refresh_token", refresh_token: REFRESH_TOKEN})
|
||||||
|
String jsonData = "{\"grant_type\":\"refresh_token\",\"refresh_token\":\"\"}";
|
||||||
|
System.out.println("POST数据(JSON字符串): " + jsonData);
|
||||||
|
System.out.println("注意:使用无效token测试错误响应格式");
|
||||||
|
System.out.println("开始请求...");
|
||||||
|
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
JsHttpClient.JsHttpResponse response = httpClient.post(tokenUrl, jsonData);
|
||||||
|
long endTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
System.out.println("请求完成,耗时: " + (endTime - startTime) + "ms");
|
||||||
|
System.out.println("状态码: " + response.statusCode());
|
||||||
|
|
||||||
|
String body = response.body();
|
||||||
|
System.out.println("响应体: " + body);
|
||||||
|
|
||||||
|
// 验证结果
|
||||||
|
assertNotNull("响应不能为null", response);
|
||||||
|
// 使用无效token应该返回400或401等错误状态码,但请求格式应该是正确的
|
||||||
|
assertTrue("状态码应该是4xx(无效token)或200(如果token有效)",
|
||||||
|
response.statusCode() >= 200 && response.statusCode() < 500);
|
||||||
|
assertNotNull("响应体不能为null", body);
|
||||||
|
|
||||||
|
// 验证响应格式(阿里云盘API通常返回JSON)
|
||||||
|
try {
|
||||||
|
Object jsonResponse = response.json();
|
||||||
|
System.out.println("响应JSON解析成功: " + jsonResponse);
|
||||||
|
assertNotNull("JSON响应不能为null", jsonResponse);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("警告:响应不是有效的JSON格式");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证请求头是否正确设置
|
||||||
|
System.out.println("验证请求头设置...");
|
||||||
|
Map<String, String> headers = httpClient.getHeaders();
|
||||||
|
assertTrue("应该设置了Content-Type", headers.containsKey("Content-Type"));
|
||||||
|
assertEquals("Content-Type应该是application/json",
|
||||||
|
"application/json", headers.get("Content-Type"));
|
||||||
|
|
||||||
|
System.out.println("✓ 测试通过 - 请求格式正确,已成功发送到阿里云盘API");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("✗ 测试失败: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
// 如果是超时或其他网络错误,说明请求格式可能有问题
|
||||||
|
if (e.getMessage() != null && e.getMessage().contains("超时")) {
|
||||||
|
fail("请求超时,可能是请求格式问题或网络问题: " + e.getMessage());
|
||||||
|
} else {
|
||||||
|
fail("阿里云盘Token接口测试失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAlipanTokenApiWithValidFormat() {
|
||||||
|
System.out.println("\n[测试21] 阿里云盘Token接口格式验证 - 使用httpbin验证请求格式");
|
||||||
|
System.out.println("通过httpbin回显验证请求格式是否与alipan.js中的格式一致");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 使用httpbin来验证请求格式
|
||||||
|
String testUrl = "https://httpbin.org/post";
|
||||||
|
System.out.println("测试URL: " + testUrl);
|
||||||
|
|
||||||
|
// 参考 alipan.js 中的请求格式
|
||||||
|
httpClient.clearHeaders(); // 清空之前的头
|
||||||
|
httpClient.putHeader("Content-Type", "application/json");
|
||||||
|
httpClient.putHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||||
|
|
||||||
|
// 完全模拟 alipan.js 中的请求体格式
|
||||||
|
String jsonData = "{\"grant_type\":\"refresh_token\",\"refresh_token\":\"test_refresh_token_12345\"}";
|
||||||
|
System.out.println("POST数据(JSON字符串): " + jsonData);
|
||||||
|
System.out.println("开始请求...");
|
||||||
|
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
JsHttpClient.JsHttpResponse response = httpClient.post(testUrl, jsonData);
|
||||||
|
long endTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
System.out.println("请求完成,耗时: " + (endTime - startTime) + "ms");
|
||||||
|
System.out.println("状态码: " + response.statusCode());
|
||||||
|
|
||||||
|
String body = response.body();
|
||||||
|
System.out.println("响应体(前800字符): " + (body != null && body.length() > 800 ? body.substring(0, 800) + "..." : body));
|
||||||
|
|
||||||
|
// 验证结果
|
||||||
|
assertNotNull("响应不能为null", response);
|
||||||
|
assertEquals("状态码应该是200", 200, response.statusCode());
|
||||||
|
assertNotNull("响应体不能为null", body);
|
||||||
|
|
||||||
|
// httpbin会回显请求数据,验证请求体是否正确发送
|
||||||
|
assertTrue("响应体应该包含grant_type字段", body.contains("grant_type"));
|
||||||
|
assertTrue("响应体应该包含refresh_token字段", body.contains("refresh_token"));
|
||||||
|
assertTrue("响应体应该包含发送的refresh_token值", body.contains("test_refresh_token_12345"));
|
||||||
|
|
||||||
|
// 验证Content-Type是否正确
|
||||||
|
assertTrue("响应体应该包含Content-Type信息", body.contains("application/json"));
|
||||||
|
|
||||||
|
// 验证User-Agent是否正确
|
||||||
|
assertTrue("响应体应该包含User-Agent信息", body.contains("Mozilla"));
|
||||||
|
|
||||||
|
System.out.println("✓ 测试通过 - 请求格式与alipan.js中的格式完全一致");
|
||||||
|
System.out.println(" - JSON请求体正确发送");
|
||||||
|
System.out.println(" - Content-Type正确设置");
|
||||||
|
System.out.println(" - User-Agent正确设置");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("✗ 测试失败: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
fail("阿里云盘Token接口格式验证失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetTimeout() {
|
public void testSetTimeout() {
|
||||||
System.out.println("\n[测试15] 设置超时时间 - setTimeout方法");
|
System.out.println("\n[测试15] 设置超时时间 - setTimeout方法");
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ export default {
|
|||||||
const editorContainer = ref(null);
|
const editorContainer = ref(null);
|
||||||
let editor = null;
|
let editor = null;
|
||||||
let monaco = null;
|
let monaco = null;
|
||||||
|
let touchHandlers = { start: null, move: null };
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
value: props.modelValue,
|
value: props.modelValue,
|
||||||
@@ -136,6 +137,46 @@ export default {
|
|||||||
if (editorContainer.value) {
|
if (editorContainer.value) {
|
||||||
editorContainer.value.style.height = props.height;
|
editorContainer.value.style.height = props.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 移动端:添加触摸缩放来调整字体大小
|
||||||
|
if (window.innerWidth <= 768 && editorContainer.value) {
|
||||||
|
let initialDistance = 0;
|
||||||
|
let initialFontSize = defaultOptions.fontSize || 14;
|
||||||
|
const minFontSize = 8;
|
||||||
|
const maxFontSize = 24;
|
||||||
|
|
||||||
|
const getTouchDistance = (touch1, touch2) => {
|
||||||
|
const dx = touch1.clientX - touch2.clientX;
|
||||||
|
const dy = touch1.clientY - touch2.clientY;
|
||||||
|
return Math.sqrt(dx * dx + dy * dy);
|
||||||
|
};
|
||||||
|
|
||||||
|
touchHandlers.start = (e) => {
|
||||||
|
if (e.touches.length === 2 && editor) {
|
||||||
|
initialDistance = getTouchDistance(e.touches[0], e.touches[1]);
|
||||||
|
initialFontSize = editor.getOption(monaco.editor.EditorOption.fontSize);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
touchHandlers.move = (e) => {
|
||||||
|
if (e.touches.length === 2 && editor) {
|
||||||
|
e.preventDefault(); // 防止页面缩放
|
||||||
|
const currentDistance = getTouchDistance(e.touches[0], e.touches[1]);
|
||||||
|
const scale = currentDistance / initialDistance;
|
||||||
|
const newFontSize = Math.round(initialFontSize * scale);
|
||||||
|
|
||||||
|
// 限制字体大小范围
|
||||||
|
const clampedFontSize = Math.max(minFontSize, Math.min(maxFontSize, newFontSize));
|
||||||
|
|
||||||
|
if (clampedFontSize !== editor.getOption(monaco.editor.EditorOption.fontSize)) {
|
||||||
|
editor.updateOptions({ fontSize: clampedFontSize });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
editorContainer.value.addEventListener('touchstart', touchHandlers.start, { passive: false });
|
||||||
|
editorContainer.value.addEventListener('touchmove', touchHandlers.move, { passive: false });
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Monaco Editor初始化失败:', error);
|
console.error('Monaco Editor初始化失败:', error);
|
||||||
console.error('错误详情:', error.stack);
|
console.error('错误详情:', error.stack);
|
||||||
@@ -179,6 +220,11 @@ export default {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
// 清理触摸事件监听器
|
||||||
|
if (editorContainer.value && touchHandlers.start && touchHandlers.move) {
|
||||||
|
editorContainer.value.removeEventListener('touchstart', touchHandlers.start);
|
||||||
|
editorContainer.value.removeEventListener('touchmove', touchHandlers.move);
|
||||||
|
}
|
||||||
if (editor) {
|
if (editor) {
|
||||||
editor.dispose();
|
editor.dispose();
|
||||||
}
|
}
|
||||||
@@ -200,10 +246,26 @@ export default {
|
|||||||
border: 1px solid #dcdfe6;
|
border: 1px solid #dcdfe6;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
/* 允许用户选择文本 */
|
||||||
|
-webkit-user-select: text;
|
||||||
|
user-select: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-editor-container :deep(.monaco-editor) {
|
.monaco-editor-container :deep(.monaco-editor) {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 移动端:禁用页面缩放,只允许编辑器字体缩放 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.monaco-editor-container {
|
||||||
|
/* 禁用页面级别的缩放,只允许编辑器内部字体缩放 */
|
||||||
|
touch-action: pan-x pan-y;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monaco-editor-container :deep(.monaco-editor) {
|
||||||
|
/* 禁用页面级别的缩放 */
|
||||||
|
touch-action: pan-x pan-y;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -400,7 +400,7 @@ export default {
|
|||||||
const data = result.data
|
const data = result.data
|
||||||
|
|
||||||
// 检查是否支持目录解析
|
// 检查是否支持目录解析
|
||||||
const supportedPans = ["iz", "lz", "fj", "ye"]
|
const supportedPans = ["iz", "lz", "fj", "ye", "le"]
|
||||||
if (!supportedPans.includes(data.shareLinkInfo.type)) {
|
if (!supportedPans.includes(data.shareLinkInfo.type)) {
|
||||||
this.$message.error("当前网盘不支持目录解析")
|
this.$message.error("当前网盘不支持目录解析")
|
||||||
return
|
return
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@ proxyConf: server-proxy
|
|||||||
# JS演练场配置
|
# JS演练场配置
|
||||||
playground:
|
playground:
|
||||||
# 是否启用演练场,默认false不启用
|
# 是否启用演练场,默认false不启用
|
||||||
enabled: false
|
enabled: true
|
||||||
# 公开模式,默认false需要密码访问,设为true则无需密码
|
# 公开模式,默认false需要密码访问,设为true则无需密码
|
||||||
public: false
|
public: false
|
||||||
# 访问密码,建议修改默认密码!
|
# 访问密码,建议修改默认密码!
|
||||||
@@ -110,4 +110,4 @@ auths:
|
|||||||
# 123网盘:配置用户名密码
|
# 123网盘:配置用户名密码
|
||||||
ye:
|
ye:
|
||||||
username:
|
username:
|
||||||
password:
|
password:
|
||||||
|
|||||||
Reference in New Issue
Block a user