mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2025-12-16 20:33:03 +00:00
1. 添加联想乐云直链解析 2. 优化代码逻辑
This commit is contained in:
@@ -16,6 +16,7 @@ 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);
|
||||||
default -> {
|
default -> {
|
||||||
throw new UnsupportedOperationException("未知分享类型");
|
throw new UnsupportedOperationException("未知分享类型");
|
||||||
}
|
}
|
||||||
@@ -38,6 +39,8 @@ public interface IPanTool {
|
|||||||
return new FjTool(url, pwd);
|
return new FjTool(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);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new UnsupportedOperationException("未知分享类型");
|
throw new UnsupportedOperationException("未知分享类型");
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package cn.qaiu.parser;
|
package cn.qaiu.parser;
|
||||||
|
|
||||||
import cn.qaiu.WebClientVertxInit;
|
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;
|
||||||
@@ -8,24 +9,61 @@ import io.vertx.ext.web.client.WebClientOptions;
|
|||||||
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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Http client
|
||||||
|
*/
|
||||||
protected WebClient client = WebClient.create(WebClientVertxInit.get());
|
protected WebClient client = WebClient.create(WebClientVertxInit.get());
|
||||||
protected WebClient clientNoRedirects = WebClient.create(WebClientVertxInit.get(), OPTIONS);
|
|
||||||
private static final WebClientOptions OPTIONS = new WebClientOptions().setFollowRedirects(false);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 +76,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 +94,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());
|
||||||
}
|
}
|
||||||
|
|||||||
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,6 @@ import cn.qaiu.parser.PanBase;
|
|||||||
import cn.qaiu.util.JsExecUtils;
|
import cn.qaiu.util.JsExecUtils;
|
||||||
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 org.openjdk.nashorn.api.scripting.ScriptObjectMirror;
|
import org.openjdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||||
@@ -55,7 +54,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;
|
||||||
@@ -75,7 +74,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引擎执行失败");
|
||||||
}
|
}
|
||||||
@@ -96,7 +95,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());
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package cn.qaiu.parser.impl;
|
|||||||
import cn.qaiu.parser.IPanTool;
|
import cn.qaiu.parser.IPanTool;
|
||||||
import cn.qaiu.parser.PanBase;
|
import cn.qaiu.parser.PanBase;
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
import io.vertx.core.Promise;
|
|
||||||
|
|
||||||
public class QkTool extends PanBase implements IPanTool {
|
public class QkTool extends PanBase implements IPanTool {
|
||||||
|
|
||||||
@@ -12,8 +11,6 @@ public class QkTool extends PanBase implements IPanTool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Future<String> parse() {
|
public Future<String> parse() {
|
||||||
Promise<String> promise = Promise.promise();
|
|
||||||
|
|
||||||
promise.complete("https://lz.qaiu.top");
|
promise.complete("https://lz.qaiu.top");
|
||||||
return promise.future();
|
return promise.future();
|
||||||
}
|
}
|
||||||
|
|||||||
79
web-service/src/main/resources/http-tools/pan-le.http
Normal file
79
web-service/src/main/resources/http-tools/pan-le.http
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
// 联想乐云(联想云服务)
|
||||||
|
|
||||||
|
### 第一步 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":"4DANWdRQsHHyiFB4a1","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 第三步
|
||||||
|
# @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=18175394-7437-4eca-8c55-40b73fc70186&ri=&ts=1701148198092&sn=30589173efacb5b493fd47e0f134309ab598252951a5a82d8292011e626b5c26
|
||||||
|
|
||||||
|
###
|
||||||
|
https://lecloud4.lenovomm.cn/dlserver/fileman/ali/sync-cloud-disk/649593714557087744.dex?KEY1=7be0212f4bd3155951942d9d62b8dfd9&KEY2=65681948&order=0&uuid=96b1edd21f4e441ca3d305e86ba714c6&cMD5=false&sorder=0&group=&ts=1701148232156&cpn=-1&cid=3b9aca4b3b9aca4c&__bc=10007&__cid=3b9aca4b3b9aca4c&__ip=60.216.19.75&__ept=1&dck=1&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
|
||||||
|
# }
|
||||||
|
#}
|
||||||
@@ -107,9 +107,30 @@ GET http://127.0.0.1:6400/parser?url=https://www.123pan.com/s/iaKtVv-6OECd.html&
|
|||||||
### 123
|
### 123
|
||||||
# @no-redirect
|
# @no-redirect
|
||||||
GET http://127.0.0.1:6400/parser?url=https://www.123pan.com/s/zF07Vv-WkHWd.html&pwd=bios
|
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
|
||||||
|
|
||||||
|
|
||||||
###
|
###
|
||||||
GET http://127.0.0.1:6400/v2/statisticsInfo
|
GET http://127.0.0.1:6400/v2/statisticsInfo
|
||||||
|
|
||||||
###
|
###
|
||||||
POST http://127.0.0.1:6400/v2/login?username=asd
|
POST http://127.0.0.1:6400/v2/login?username=asd
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user