mirror of
https://github.com/qaiu/netdisk-fast-download.git
synced 2025-12-18 21:33:03 +00:00
@@ -8,7 +8,11 @@ public interface ConfigConstant {
|
|||||||
String SERVER = "server";
|
String SERVER = "server";
|
||||||
String CACHE = "cache";
|
String CACHE = "cache";
|
||||||
|
|
||||||
|
String PROXY_SERVER = "proxy-server";
|
||||||
|
|
||||||
String PROXY = "proxy";
|
String PROXY = "proxy";
|
||||||
|
|
||||||
|
String AUTHS = "auths";
|
||||||
String GLOBAL_CONFIG = "globalConfig";
|
String GLOBAL_CONFIG = "globalConfig";
|
||||||
String CUSTOM_CONFIG = "customConfig";
|
String CUSTOM_CONFIG = "customConfig";
|
||||||
String ASYNC_SERVICE_INSTANCES = "asyncServiceInstances";
|
String ASYNC_SERVICE_INSTANCES = "asyncServiceInstances";
|
||||||
|
|||||||
@@ -72,6 +72,9 @@ public class FileInfo {
|
|||||||
//预览地址
|
//预览地址
|
||||||
private String previewUrl;
|
private String previewUrl;
|
||||||
|
|
||||||
|
// 文件hash默认类型为md5
|
||||||
|
private String hash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 扩展参数
|
* 扩展参数
|
||||||
*/
|
*/
|
||||||
@@ -210,6 +213,15 @@ public class FileInfo {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getHash() {
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileInfo setHash(String hash) {
|
||||||
|
this.hash = hash;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<String, Object> getExtParameters() {
|
public Map<String, Object> getExtParameters() {
|
||||||
return extParameters;
|
return extParameters;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -225,7 +225,6 @@ public class LzTool extends PanBase {
|
|||||||
.setParserUrl(getDomainName() + "/d/" + panType + "/" + id)
|
.setParserUrl(getDomainName() + "/d/" + panType + "/" + id)
|
||||||
.setPreviewUrl(String.format("%s/v2/view/%s/%s", getDomainName(),
|
.setPreviewUrl(String.format("%s/v2/view/%s/%s", getDomainName(),
|
||||||
shareLinkInfo.getType(), id));
|
shareLinkInfo.getType(), id));
|
||||||
;
|
|
||||||
log.debug("文件信息: {}", fileInfo);
|
log.debug("文件信息: {}", fileInfo);
|
||||||
list.add(fileInfo);
|
list.add(fileInfo);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,10 +4,13 @@ import cn.qaiu.WebClientVertxInit;
|
|||||||
import cn.qaiu.entity.FileInfo;
|
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 cn.qaiu.util.HeaderUtils;
|
import cn.qaiu.util.HeaderUtils;
|
||||||
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;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.core.json.pointer.JsonPointer;
|
||||||
import io.vertx.ext.web.client.WebClient;
|
import io.vertx.ext.web.client.WebClient;
|
||||||
import io.vertx.uritemplate.UriTemplate;
|
import io.vertx.uritemplate.UriTemplate;
|
||||||
|
|
||||||
@@ -75,7 +78,18 @@ public class PvyyTool extends PanBase {
|
|||||||
.putHeaders(header)
|
.putHeaders(header)
|
||||||
.send().onSuccess(res -> {
|
.send().onSuccess(res -> {
|
||||||
try {
|
try {
|
||||||
String id = asJson(res).getJsonObject("data").getJsonObject("data").getString("id");
|
JsonObject resJson = asJson(res);
|
||||||
|
if (!resJson.containsKey("code") || resJson.getInteger("code") != 0) {
|
||||||
|
fail("获取文件信息失败: " + resJson.getString("message"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JsonObject fileData = resJson.getJsonObject("data").getJsonObject("data");
|
||||||
|
if (fileData == null) {
|
||||||
|
fail("文件数据为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setFileInfo(fileData);
|
||||||
|
String id = fileData.getString("id");
|
||||||
|
|
||||||
client.getAbs(UriTemplate.of(apiUrl))
|
client.getAbs(UriTemplate.of(apiUrl))
|
||||||
.setTemplateParam("key", shareLinkInfo.getShareKey())
|
.setTemplateParam("key", shareLinkInfo.getShareKey())
|
||||||
@@ -97,6 +111,23 @@ public class PvyyTool extends PanBase {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setFileInfo(JsonObject fileData) {
|
||||||
|
JsonObject attributes = fileData.getJsonObject("attributes");
|
||||||
|
JsonObject user = (JsonObject)(JsonPointer.from("/relationships/user/data").queryJson(fileData));
|
||||||
|
int downCount = (Integer)(JsonPointer.from("/relationships/shared/data/attributes/down").queryJson(fileData));
|
||||||
|
String filesize = attributes.getString("filesize");
|
||||||
|
FileInfo fileInfo = new FileInfo()
|
||||||
|
.setFileId(fileData.getString("id"))
|
||||||
|
.setFileName(attributes.getString("basename"))
|
||||||
|
.setFileType(attributes.getString("mimetype"))
|
||||||
|
.setPanType(shareLinkInfo.getType())
|
||||||
|
.setCreateBy(user.getString("email"))
|
||||||
|
.setDownloadCount(downCount)
|
||||||
|
.setSize(FileSizeConverter.convertToBytes(filesize))
|
||||||
|
.setSizeStr(filesize);
|
||||||
|
shareLinkInfo.getOtherParam().put("fileInfo", fileInfo);
|
||||||
|
}
|
||||||
|
|
||||||
private static final String DIR_API = "https://www.vyuyun.com/apiv1/share/folders/809Pt6/bMjnUg?sort=created_at&direction=DESC&password={pwd}";
|
private static final String DIR_API = "https://www.vyuyun.com/apiv1/share/folders/809Pt6/bMjnUg?sort=created_at&direction=DESC&password={pwd}";
|
||||||
private static final String SHARE_TYPE_API = "https://www.vyuyun.com/apiv1/share/info/{key}?password={pwd}";
|
private static final String SHARE_TYPE_API = "https://www.vyuyun.com/apiv1/share/info/{key}?password={pwd}";
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -7,8 +7,17 @@ public class FileSizeConverter {
|
|||||||
throw new IllegalArgumentException("Invalid file size string");
|
throw new IllegalArgumentException("Invalid file size string");
|
||||||
}
|
}
|
||||||
|
|
||||||
sizeStr = sizeStr.trim().toUpperCase();
|
sizeStr = sizeStr.replace(",","").trim().toUpperCase();
|
||||||
char unit = sizeStr.charAt(sizeStr.length() - 1);
|
// 判断是2位单位还是1位单位
|
||||||
|
// 判断单位是否为2位
|
||||||
|
int unitIndex = sizeStr.length() - 1;
|
||||||
|
char unit = sizeStr.charAt(unitIndex);
|
||||||
|
if (Character.isLetter(sizeStr.charAt(unitIndex - 1))) {
|
||||||
|
unit = sizeStr.charAt(unitIndex - 1);
|
||||||
|
sizeStr = sizeStr.substring(0, unitIndex - 1);
|
||||||
|
} else {
|
||||||
|
sizeStr = sizeStr.substring(0, unitIndex);
|
||||||
|
}
|
||||||
double size = Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 1));
|
double size = Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 1));
|
||||||
|
|
||||||
return switch (unit) {
|
return switch (unit) {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "^2.3.1",
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
"@vueuse/core": "^11.2.0",
|
"@vueuse/core": "^11.2.0",
|
||||||
"axios": "^1.7.4",
|
"axios": "1.11.0",
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"element-plus": "^2.8.7",
|
"element-plus": "^2.8.7",
|
||||||
|
|||||||
@@ -153,6 +153,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<script>
|
||||||
|
const saved = localStorage.getItem('isDarkMode') === 'true'
|
||||||
|
const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||||
|
if (saved || (!saved && systemDark)) {
|
||||||
|
document.body.classList.add('dark-theme')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app" :class="{ 'dark-theme': isDarkMode }">
|
<div id="app" v-cloak :class="{ 'dark-theme': isDarkMode }">
|
||||||
<!-- <el-dialog
|
<!-- <el-dialog
|
||||||
v-model="showRiskDialog"
|
v-model="showRiskDialog"
|
||||||
title="使用本网站您应改同意"
|
title="使用本网站您应改同意"
|
||||||
@@ -293,6 +293,9 @@ export default {
|
|||||||
// 主题切换
|
// 主题切换
|
||||||
handleThemeChange(isDark) {
|
handleThemeChange(isDark) {
|
||||||
this.isDarkMode = isDark
|
this.isDarkMode = isDark
|
||||||
|
document.body.classList.toggle('dark-theme', isDark)
|
||||||
|
window.localStorage.setItem('isDarkMode', isDark)
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 验证输入
|
// 验证输入
|
||||||
@@ -600,6 +603,8 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
[v-cloak] { display: none; }
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: #f5f7fa;
|
background-color: #f5f7fa;
|
||||||
color: #2c3e50;
|
color: #2c3e50;
|
||||||
|
|||||||
@@ -3,29 +3,38 @@ package cn.qaiu.lz.common.cache;
|
|||||||
import cn.qaiu.db.pool.JDBCPoolInit;
|
import cn.qaiu.db.pool.JDBCPoolInit;
|
||||||
import cn.qaiu.db.pool.JDBCType;
|
import cn.qaiu.db.pool.JDBCType;
|
||||||
import cn.qaiu.lz.web.model.CacheLinkInfo;
|
import cn.qaiu.lz.web.model.CacheLinkInfo;
|
||||||
|
import cn.qaiu.lz.web.model.PanFileInfo;
|
||||||
|
import cn.qaiu.lz.web.model.PanFileInfoRowMapper;
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
import io.vertx.core.Promise;
|
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.Pool;
|
||||||
import io.vertx.sqlclient.Row;
|
import io.vertx.sqlclient.Row;
|
||||||
|
import io.vertx.sqlclient.RowSet;
|
||||||
import io.vertx.sqlclient.templates.SqlTemplate;
|
import io.vertx.sqlclient.templates.SqlTemplate;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class CacheManager {
|
public class CacheManager {
|
||||||
private final JDBCPool jdbcPool = JDBCPoolInit.instance().getPool();
|
private final Pool jdbcPool = JDBCPoolInit.instance().getPool();
|
||||||
private final JDBCType jdbcType = JDBCPoolInit.instance().getType();
|
private final JDBCType jdbcType = JDBCPoolInit.instance().getType();
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(CacheManager.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(CacheManager.class);
|
||||||
|
|
||||||
public Future<CacheLinkInfo> get(String cacheKey) {
|
public Future<CacheLinkInfo> get(String cacheKey) {
|
||||||
String sql = "SELECT share_key as shareKey, direct_link as directLink, expiration FROM cache_link_info WHERE share_key = #{share_key}";
|
String sql = "SELECT share_key as shareKey, direct_link as directLink, expiration FROM cache_link_info WHERE share_key = #{share_key}";
|
||||||
|
String sql2 = "SELECT * FROM pan_file_info WHERE share_key = #{share_key}";
|
||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.put("share_key", cacheKey);
|
params.put("share_key", cacheKey);
|
||||||
Promise<CacheLinkInfo> promise = Promise.promise();
|
Promise<CacheLinkInfo> promise = Promise.promise();
|
||||||
|
|
||||||
|
Future<RowSet<PanFileInfo>> execute = SqlTemplate.forQuery(jdbcPool, sql2)
|
||||||
|
.mapTo(PanFileInfoRowMapper.INSTANCE)
|
||||||
|
.execute(params);
|
||||||
SqlTemplate.forQuery(jdbcPool, sql)
|
SqlTemplate.forQuery(jdbcPool, sql)
|
||||||
.mapTo(CacheLinkInfo.class)
|
.mapTo(CacheLinkInfo.class)
|
||||||
.execute(params)
|
.execute(params)
|
||||||
@@ -34,10 +43,18 @@ public class CacheManager {
|
|||||||
if (rows.size() > 0) {
|
if (rows.size() > 0) {
|
||||||
cacheHit = rows.iterator().next();
|
cacheHit = rows.iterator().next();
|
||||||
cacheHit.setCacheHit(true);
|
cacheHit.setCacheHit(true);
|
||||||
|
execute.onSuccess(r2 -> {
|
||||||
|
if (r2.size() > 0) {
|
||||||
|
cacheHit.setFileInfo(r2.iterator().next().toFileInfo());
|
||||||
|
}
|
||||||
|
promise.complete(cacheHit);
|
||||||
|
}).onFailure(e -> {
|
||||||
|
promise.complete(cacheHit);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
cacheHit = new CacheLinkInfo(JsonObject.of("cacheHit", false, "shareKey", cacheKey));
|
cacheHit = new CacheLinkInfo(JsonObject.of("cacheHit", false, "shareKey", cacheKey));
|
||||||
|
promise.complete(cacheHit);
|
||||||
}
|
}
|
||||||
promise.complete(cacheHit);
|
|
||||||
}).onFailure(e->{
|
}).onFailure(e->{
|
||||||
promise.fail(e);
|
promise.fail(e);
|
||||||
LOGGER.error("cache get:", e);
|
LOGGER.error("cache get:", e);
|
||||||
@@ -47,7 +64,7 @@ public class CacheManager {
|
|||||||
|
|
||||||
|
|
||||||
// 插入或更新缓存数据
|
// 插入或更新缓存数据
|
||||||
public Future<Void> cacheShareLink(CacheLinkInfo cacheLinkInfo) {
|
public void cacheShareLink(CacheLinkInfo cacheLinkInfo) {
|
||||||
String sql;
|
String sql;
|
||||||
if (jdbcType == JDBCType.MySQL) {
|
if (jdbcType == JDBCType.MySQL) {
|
||||||
sql = """
|
sql = """
|
||||||
@@ -63,12 +80,53 @@ public class CacheManager {
|
|||||||
"VALUES (#{shareKey}, #{directLink}, #{expiration})";
|
"VALUES (#{shareKey}, #{directLink}, #{expiration})";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 直接传递 CacheLinkInfo 实体类
|
// 直接传递 CacheLinkInfo 实体类
|
||||||
return SqlTemplate.forUpdate(jdbcPool, sql)
|
SqlTemplate.forUpdate(jdbcPool, sql)
|
||||||
.mapFrom(CacheLinkInfo.class) // 将实体类映射为 Tuple 参数
|
.mapFrom(CacheLinkInfo.class) // 将实体类映射为 Tuple 参数
|
||||||
.execute(cacheLinkInfo)
|
.execute(cacheLinkInfo).onSuccess(result -> {
|
||||||
.mapEmpty();
|
if (result.rowCount() > 0) {
|
||||||
|
LOGGER.debug("Cache link info updated for shareKey: {}", cacheLinkInfo.getShareKey());
|
||||||
|
} else {
|
||||||
|
LOGGER.warn("No rows affected when updating cache link info for shareKey: {}", cacheLinkInfo.getShareKey());
|
||||||
|
}
|
||||||
|
}).onFailure(Throwable::printStackTrace);
|
||||||
|
|
||||||
|
if (cacheLinkInfo.getFileInfo() != null) {
|
||||||
|
String sql2 = """
|
||||||
|
INSERT IGNORE INTO pan_file_info (
|
||||||
|
share_key, file_name, file_id, file_icon, size, size_str, file_type,
|
||||||
|
file_path, create_time, update_time, create_by, description, download_count,
|
||||||
|
pan_type, parser_url, preview_url, hash
|
||||||
|
) VALUES (
|
||||||
|
#{shareKey}, #{fileName}, #{fileId}, #{fileIcon}, #{size}, #{sizeStr}, #{fileType},
|
||||||
|
#{filePath}, #{createTime}, #{updateTime}, #{createBy}, #{description}, #{downloadCount},
|
||||||
|
#{panType}, #{parserUrl}, #{previewUrl}, #{hash}
|
||||||
|
);
|
||||||
|
""";
|
||||||
|
// 判断文件信息是否缓存
|
||||||
|
SqlTemplate
|
||||||
|
.forQuery(jdbcPool, "SELECT count(1) AS count FROM pan_file_info WHERE share_key = #{share_key};")
|
||||||
|
.mapTo(Row::toJson)
|
||||||
|
.execute(Collections.singletonMap("share_key", cacheLinkInfo.getShareKey()))
|
||||||
|
.onSuccess(rows -> {
|
||||||
|
JsonObject row = rows.iterator().next();
|
||||||
|
int count = row.getInteger("count");
|
||||||
|
if (count == 0) {
|
||||||
|
// 没有缓存,执行插入
|
||||||
|
PanFileInfo fileInfo = PanFileInfo.fromFileInfo(cacheLinkInfo.getFileInfo());
|
||||||
|
fileInfo.setShareKey(cacheLinkInfo.getShareKey());
|
||||||
|
SqlTemplate.forUpdate(jdbcPool, sql2)
|
||||||
|
.mapFrom(PanFileInfo.class) // 将实体类映射为 Tuple 参数
|
||||||
|
.execute(fileInfo).onSuccess(result -> {
|
||||||
|
if (result.rowCount() > 0) {
|
||||||
|
LOGGER.debug("Pan file info inserted for shareKey: {}", cacheLinkInfo.getShareKey());
|
||||||
|
} else {
|
||||||
|
LOGGER.warn("No rows affected when inserting pan file info for shareKey: {}", cacheLinkInfo.getShareKey());
|
||||||
|
}
|
||||||
|
}).onFailure(Throwable::printStackTrace);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 写入网盘厂商API解析次数
|
// 写入网盘厂商API解析次数
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
package cn.qaiu.lz.common.util;
|
package cn.qaiu.lz.common.util;
|
||||||
|
|
||||||
|
import cn.qaiu.parser.ParserCreate;
|
||||||
|
import cn.qaiu.vx.core.util.ConfigConstant;
|
||||||
|
import cn.qaiu.vx.core.util.SharedDataUtil;
|
||||||
|
import cn.qaiu.vx.core.util.VertxHolder;
|
||||||
import io.vertx.core.MultiMap;
|
import io.vertx.core.MultiMap;
|
||||||
import io.vertx.core.http.HttpServerRequest;
|
import io.vertx.core.http.HttpServerRequest;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.core.shareddata.LocalMap;
|
||||||
|
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@@ -72,4 +78,42 @@ public class URLParamUtil {
|
|||||||
|
|
||||||
return urlBuilder.toString();
|
return urlBuilder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加共享链接的其他参数到ParserCreate对象中
|
||||||
|
* @param parserCreate ParserCreate对象,包含共享链接信息
|
||||||
|
*/
|
||||||
|
public static void addParam(ParserCreate parserCreate) {
|
||||||
|
LocalMap<Object, Object> localMap = VertxHolder.getVertxInstance().sharedData()
|
||||||
|
.getLocalMap(ConfigConstant.LOCAL);
|
||||||
|
|
||||||
|
String type = parserCreate.getShareLinkInfo().getType();
|
||||||
|
if (localMap.containsKey(ConfigConstant.PROXY)) {
|
||||||
|
JsonObject proxy = (JsonObject) localMap.get(ConfigConstant.PROXY);
|
||||||
|
if (proxy.containsKey(type)) {
|
||||||
|
parserCreate.getShareLinkInfo().getOtherParam().put(ConfigConstant.PROXY, proxy.getJsonObject(type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (localMap.containsKey(ConfigConstant.AUTHS)) {
|
||||||
|
JsonObject auths = (JsonObject) localMap.get(ConfigConstant.AUTHS);
|
||||||
|
if (auths.containsKey(type)) {
|
||||||
|
// 需要处理引号
|
||||||
|
MultiMap entries = MultiMap.caseInsensitiveMultiMap();
|
||||||
|
JsonObject jsonObject = auths.getJsonObject(type);
|
||||||
|
if (jsonObject != null) {
|
||||||
|
jsonObject.forEach(entity -> {
|
||||||
|
if (entity == null || entity.getValue() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
entries.set(entity.getKey(), entity.getValue().toString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
parserCreate.getShareLinkInfo().getOtherParam().put(ConfigConstant.AUTHS, entries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String linkPrefix = SharedDataUtil.getJsonConfig("server").getString("domainName");
|
||||||
|
parserCreate.getShareLinkInfo().getOtherParam().put("domainName", linkPrefix);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ import cn.qaiu.db.ddl.Table;
|
|||||||
import cn.qaiu.db.ddl.TableGenIgnore;
|
import cn.qaiu.db.ddl.TableGenIgnore;
|
||||||
import cn.qaiu.entity.FileInfo;
|
import cn.qaiu.entity.FileInfo;
|
||||||
import cn.qaiu.lz.common.ToJson;
|
import cn.qaiu.lz.common.ToJson;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
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 io.vertx.core.json.jackson.DatabindCodec;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@@ -66,6 +68,11 @@ public class CacheLinkInfo implements ToJson {
|
|||||||
if (json.containsKey("expiration")) {
|
if (json.containsKey("expiration")) {
|
||||||
this.setExpiration(json.getLong("expiration"));
|
this.setExpiration(json.getLong("expiration"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (json.containsKey("fileInfo")) {
|
||||||
|
ObjectMapper mapper = DatabindCodec.mapper(); // Vert.x 自带的 mapper
|
||||||
|
this.setFileInfo(mapper.convertValue(json.getJsonObject("fileInfo"), FileInfo.class));
|
||||||
|
}
|
||||||
this.setCacheHit(json.getBoolean("cacheHit", false));
|
this.setCacheHit(json.getBoolean("cacheHit", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
163
web-service/src/main/java/cn/qaiu/lz/web/model/PanFileInfo.java
Normal file
163
web-service/src/main/java/cn/qaiu/lz/web/model/PanFileInfo.java
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
package cn.qaiu.lz.web.model;
|
||||||
|
|
||||||
|
import cn.qaiu.db.ddl.Table;
|
||||||
|
import cn.qaiu.entity.FileInfo;
|
||||||
|
import io.vertx.codegen.annotations.DataObject;
|
||||||
|
import io.vertx.codegen.format.SnakeCase;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.sqlclient.templates.annotations.RowMapped;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="https://qaiu.top">QAIU</a>
|
||||||
|
* @date 2025/8/4 12:38
|
||||||
|
*/
|
||||||
|
@Table(keyFields = "share_key")
|
||||||
|
@DataObject
|
||||||
|
@RowMapped(formatter = SnakeCase.class)
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Data
|
||||||
|
public class PanFileInfo {
|
||||||
|
|
||||||
|
String shareKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件名
|
||||||
|
*/
|
||||||
|
private String fileName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件ID
|
||||||
|
*/
|
||||||
|
private String fileId;
|
||||||
|
|
||||||
|
private String fileIcon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件大小(byte)
|
||||||
|
*/
|
||||||
|
private Long size;
|
||||||
|
|
||||||
|
|
||||||
|
private String sizeStr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
private String fileType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件路径
|
||||||
|
*/
|
||||||
|
private String filePath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建(上传)时间 yyyy-MM-dd HH:mm:ss格式
|
||||||
|
*/
|
||||||
|
private String createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上次修改时间
|
||||||
|
*/
|
||||||
|
private String updateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建者
|
||||||
|
*/
|
||||||
|
private String createBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件描述
|
||||||
|
*/
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载次数
|
||||||
|
*/
|
||||||
|
private Integer downloadCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网盘标识
|
||||||
|
*/
|
||||||
|
private String panType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nfd下载链接(可能获取不到)
|
||||||
|
* note: 不是下载直链
|
||||||
|
*/
|
||||||
|
private String parserUrl;
|
||||||
|
|
||||||
|
//预览地址
|
||||||
|
private String previewUrl;
|
||||||
|
|
||||||
|
// 文件hash默认类型为md5
|
||||||
|
private String hash;
|
||||||
|
|
||||||
|
public PanFileInfo(JsonObject jsonObject) {
|
||||||
|
this.shareKey = jsonObject.getString("shareKey");
|
||||||
|
this.fileName = jsonObject.getString("fileName");
|
||||||
|
this.fileId = jsonObject.getString("fileId");
|
||||||
|
this.fileIcon = jsonObject.getString("fileIcon");
|
||||||
|
this.size = jsonObject.getLong("size");
|
||||||
|
this.sizeStr = jsonObject.getString("sizeStr");
|
||||||
|
this.fileType = jsonObject.getString("fileType");
|
||||||
|
this.filePath = jsonObject.getString("filePath");
|
||||||
|
this.createTime = jsonObject.getString("createTime");
|
||||||
|
this.updateTime = jsonObject.getString("updateTime");
|
||||||
|
this.createBy = jsonObject.getString("createBy");
|
||||||
|
this.description = jsonObject.getString("description");
|
||||||
|
this.downloadCount = jsonObject.getInteger("downloadCount");
|
||||||
|
this.panType = jsonObject.getString("panType");
|
||||||
|
this.parserUrl = jsonObject.getString("parserUrl");
|
||||||
|
this.previewUrl = jsonObject.getString("previewUrl");
|
||||||
|
this.hash = jsonObject.getString("hash");
|
||||||
|
}
|
||||||
|
public static PanFileInfo fromFileInfo(FileInfo info) {
|
||||||
|
PanFileInfo panFileInfo = new PanFileInfo();
|
||||||
|
if (info == null) {
|
||||||
|
return panFileInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拷贝 FileInfo 的字段
|
||||||
|
panFileInfo.setFileName(info.getFileName());
|
||||||
|
panFileInfo.setFileId(info.getFileId());
|
||||||
|
panFileInfo.setFileIcon(info.getFileIcon());
|
||||||
|
panFileInfo.setSize(info.getSize());
|
||||||
|
panFileInfo.setSizeStr(info.getSizeStr());
|
||||||
|
panFileInfo.setFileType(info.getFileType());
|
||||||
|
panFileInfo.setFilePath(info.getFilePath());
|
||||||
|
panFileInfo.setCreateTime(info.getCreateTime());
|
||||||
|
panFileInfo.setUpdateTime(info.getUpdateTime());
|
||||||
|
panFileInfo.setCreateBy(info.getCreateBy());
|
||||||
|
panFileInfo.setDescription(info.getDescription());
|
||||||
|
panFileInfo.setDownloadCount(info.getDownloadCount());
|
||||||
|
panFileInfo.setPanType(info.getPanType());
|
||||||
|
panFileInfo.setParserUrl(info.getParserUrl());
|
||||||
|
panFileInfo.setPreviewUrl(info.getPreviewUrl());
|
||||||
|
panFileInfo.setHash(info.getHash());
|
||||||
|
return panFileInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileInfo toFileInfo() {
|
||||||
|
FileInfo fileInfo = new FileInfo();
|
||||||
|
|
||||||
|
fileInfo.setFileName(this.getFileName());
|
||||||
|
fileInfo.setFileId(this.getFileId());
|
||||||
|
fileInfo.setFileIcon(this.getFileIcon());
|
||||||
|
fileInfo.setSize(this.getSize());
|
||||||
|
fileInfo.setSizeStr(this.getSizeStr());
|
||||||
|
fileInfo.setFileType(this.getFileType());
|
||||||
|
fileInfo.setFilePath(this.getFilePath());
|
||||||
|
fileInfo.setCreateTime(this.getCreateTime());
|
||||||
|
fileInfo.setUpdateTime(this.getUpdateTime());
|
||||||
|
fileInfo.setCreateBy(this.getCreateBy());
|
||||||
|
fileInfo.setDescription(this.getDescription());
|
||||||
|
fileInfo.setDownloadCount(this.getDownloadCount());
|
||||||
|
fileInfo.setPanType(this.getPanType());
|
||||||
|
fileInfo.setParserUrl(this.getParserUrl());
|
||||||
|
fileInfo.setPreviewUrl(this.getPreviewUrl());
|
||||||
|
fileInfo.setHash(this.getHash());
|
||||||
|
return fileInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,38 +1,33 @@
|
|||||||
package cn.qaiu.lz.web.service.impl;
|
package cn.qaiu.lz.web.service.impl;
|
||||||
|
|
||||||
|
import cn.qaiu.entity.FileInfo;
|
||||||
import cn.qaiu.entity.ShareLinkInfo;
|
import cn.qaiu.entity.ShareLinkInfo;
|
||||||
import cn.qaiu.lz.common.cache.CacheConfigLoader;
|
import cn.qaiu.lz.common.cache.CacheConfigLoader;
|
||||||
import cn.qaiu.lz.common.cache.CacheManager;
|
import cn.qaiu.lz.common.cache.CacheManager;
|
||||||
import cn.qaiu.lz.common.cache.CacheTotalField;
|
import cn.qaiu.lz.common.cache.CacheTotalField;
|
||||||
|
import cn.qaiu.lz.common.util.URLParamUtil;
|
||||||
import cn.qaiu.lz.web.model.CacheLinkInfo;
|
import cn.qaiu.lz.web.model.CacheLinkInfo;
|
||||||
import cn.qaiu.lz.web.service.CacheService;
|
import cn.qaiu.lz.web.service.CacheService;
|
||||||
|
import cn.qaiu.parser.IPanTool;
|
||||||
import cn.qaiu.parser.ParserCreate;
|
import cn.qaiu.parser.ParserCreate;
|
||||||
import cn.qaiu.vx.core.annotaions.Service;
|
import cn.qaiu.vx.core.annotaions.Service;
|
||||||
import cn.qaiu.vx.core.util.ConfigConstant;
|
|
||||||
import cn.qaiu.vx.core.util.VertxHolder;
|
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
import io.vertx.core.Promise;
|
import io.vertx.core.Promise;
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
import io.vertx.core.shareddata.LocalMap;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.time.DateFormatUtils;
|
import org.apache.commons.lang3.time.DateFormatUtils;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@Slf4j
|
||||||
public class CacheServiceImpl implements CacheService {
|
public class CacheServiceImpl implements CacheService {
|
||||||
|
|
||||||
private final CacheManager cacheManager = new CacheManager();
|
private final CacheManager cacheManager = new CacheManager();
|
||||||
|
|
||||||
private Future<CacheLinkInfo> getAndSaveCachedShareLink(ParserCreate parserCreate) {
|
private Future<CacheLinkInfo> getAndSaveCachedShareLink(ParserCreate parserCreate) {
|
||||||
LocalMap<Object, Object> localMap = VertxHolder.getVertxInstance().sharedData()
|
|
||||||
.getLocalMap(ConfigConstant.LOCAL);
|
URLParamUtil.addParam(parserCreate);
|
||||||
if (localMap.containsKey(ConfigConstant.PROXY)) {
|
|
||||||
JsonObject proxy = (JsonObject) localMap.get(ConfigConstant.PROXY);
|
|
||||||
String type = parserCreate.getShareLinkInfo().getType();
|
|
||||||
if (proxy.containsKey(type)) {
|
|
||||||
parserCreate.getShareLinkInfo().getOtherParam().put(ConfigConstant.PROXY, proxy.getJsonObject(type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Promise<CacheLinkInfo> promise = Promise.promise();
|
Promise<CacheLinkInfo> promise = Promise.promise();
|
||||||
// 构建组合的缓存key
|
// 构建组合的缓存key
|
||||||
@@ -46,20 +41,36 @@ public class CacheServiceImpl implements CacheService {
|
|||||||
// parse
|
// parse
|
||||||
result.setCacheHit(false);
|
result.setCacheHit(false);
|
||||||
result.setExpiration(0L);
|
result.setExpiration(0L);
|
||||||
parserCreate.createTool().parse().onSuccess(redirectUrl -> {
|
IPanTool tool;
|
||||||
|
try {
|
||||||
|
tool = parserCreate.createTool();
|
||||||
|
} catch (Exception e) {
|
||||||
|
promise.fail(e.getCause().getCause());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tool.parse().onSuccess(redirectUrl -> {
|
||||||
long expires = System.currentTimeMillis() +
|
long expires = System.currentTimeMillis() +
|
||||||
CacheConfigLoader.getDuration(shareLinkInfo.getType()) * 60 * 1000L;
|
CacheConfigLoader.getDuration(shareLinkInfo.getType()) * 60 * 1000L;
|
||||||
result.setDirectLink(redirectUrl);
|
result.setDirectLink(redirectUrl);
|
||||||
// result.setExpires(generateDate(expires));
|
|
||||||
promise.complete(result);
|
|
||||||
// 更新缓存
|
|
||||||
// 将直链存储到缓存
|
|
||||||
CacheLinkInfo cacheLinkInfo = new CacheLinkInfo(JsonObject.of(
|
CacheLinkInfo cacheLinkInfo = new CacheLinkInfo(JsonObject.of(
|
||||||
"directLink", redirectUrl,
|
"directLink", redirectUrl,
|
||||||
"expiration", expires,
|
"expiration", expires,
|
||||||
"shareKey", cacheKey
|
"shareKey", cacheKey
|
||||||
));
|
));
|
||||||
cacheManager.cacheShareLink(cacheLinkInfo).onFailure(Throwable::printStackTrace);
|
if (shareLinkInfo.getOtherParam().containsKey("fileInfo")) {
|
||||||
|
try {
|
||||||
|
FileInfo fileInfo = (FileInfo) shareLinkInfo.getOtherParam().get("fileInfo");
|
||||||
|
result.setFileInfo(fileInfo);
|
||||||
|
cacheLinkInfo.setFileInfo(fileInfo);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
log.error("文件对象转换异常");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
promise.complete(result);
|
||||||
|
// 更新缓存
|
||||||
|
// 将直链存储到缓存
|
||||||
|
cacheManager.cacheShareLink(cacheLinkInfo);
|
||||||
cacheManager.updateTotalByField(cacheKey, CacheTotalField.API_PARSER_TOTAL).onFailure(Throwable::printStackTrace);
|
cacheManager.updateTotalByField(cacheKey, CacheTotalField.API_PARSER_TOTAL).onFailure(Throwable::printStackTrace);
|
||||||
}).onFailure(promise::fail);
|
}).onFailure(promise::fail);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user