Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 新增dwg文件预览 #149

Merged
merged 6 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,31 @@ FROM nvidia/cuda:11.7.1-base-ubuntu22.04 AS base
# 设置非交互式安装,避免 tzdata 等包的配置暂停
ENV DEBIAN_FRONTEND=noninteractive

COPY docker/mxcad_x86_64.zip /jmalcloud/

# 安装 wget 和 tesseract,并配置时区和 locales
RUN apt-get update && \
apt-get install -y --no-install-recommends wget locales tesseract-ocr p7zip-full unrar libheif-examples && \
apt-get install -y --no-install-recommends wget unzip locales tesseract-ocr p7zip-full unrar libheif-examples && \
locale-gen en_US.UTF-8 && \
update-locale LANG=en_US.UTF-8 && \
# 下载并安装 jellyfin-ffmpeg
ARCH=$(dpkg --print-architecture) && \
wget https://repo.jellyfin.org/files/ffmpeg/ubuntu/latest-5.x/${ARCH}/jellyfin-ffmpeg5_5.1.4-3-jammy_${ARCH}.deb && \
dpkg -i jellyfin-ffmpeg5_5.1.4-3-jammy_${ARCH}.deb || apt-get install -fy && \
# 安装 mxcad
unzip -o /jmalcloud/mxcad_x86_64.zip -d /usr/local/ && \
rm -f /jmalcloud/mxcad_x86_64.zip && \
rm -rf /usr/local/__MACOSX/ && \
mv /usr/local/x86_64/ /usr/local/mxcad && \
chmod -R 777 /usr/local/mxcad/mxcadassembly && \
chmod -R 777 ./mx/so/* && \
cp -r -f ./mx/locale /usr/local/share/locale && \
# 卸载 wget 并清理下载的文件和APT缓存
rm -f jellyfin-ffmpeg5_5.1.4-3-jammy_${ARCH}.deb && \
apt-get remove -y wget && \
apt-get remove -y wget unzip && \
apt-get clean && \
rm -f jellyfin-ffmpeg5_5.1.4-3-jammy_${ARCH}.deb && \
rm -rf /var/lib/apt/lists/*


# 将/usr/lib/jellyfin-ffmpeg添加到PATH
ENV PATH=/usr/lib/jellyfin-ffmpeg:$PATH

Expand All @@ -41,12 +50,11 @@ RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

RUN mkdir -p /jmalcloud/files /jmalcloud/tess4j/datapath

ADD docker/ip2region.xdb /jmalcloud/

ADD tess4j/datapath/chi_sim.traineddata /jmalcloud/tess4j/datapath/

COPY docker/ip2region.xdb /jmalcloud/

ADD target/lib /usr/local/clouddisk-lib
COPY tess4j/datapath/chi_sim.traineddata /jmalcloud/tess4j/datapath/
COPY target/lib /usr/local/clouddisk-lib

# 更新 PATH 和 LD_LIBRARY_PATH
ENV PATH="/opt/java/openjdk/bin:${PATH}"
Expand Down
Binary file added docker/mxcad_x86_64.zip
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,15 @@ public void packageDownload(HttpServletRequest request, HttpServletResponse resp
}
}

@Operation(summary = "获取dwg文件对应的mxweb文件")
@GetMapping("/view/mxweb/{fileId}")
@Permission("cloud:file:list")
@LogOperatingFun(logType = LogOperation.Type.BROWSE)
public ResponseEntity<Object> getMxweb(@PathVariable String fileId) {
Optional<FileDocument> file = fileService.getMxweb(fileId);
return file.map(fileService::getObjectResponseEntity).orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND).body("找不到该文件"));
}

@Operation(summary = "显示缩略图")
@GetMapping("/view/thumbnail")
@Permission("cloud:file:list")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,15 @@ public ResponseEntity<Object> publicThumbnail(String id, Boolean showCover, Http
return thumbnail(id, showCover, request);
}

@Operation(summary = "获取dwg文件对应的mxweb文件")
@GetMapping("/public/s/view/mxweb/{fileId}/{shareId}")
@LogOperatingFun(logType = LogOperation.Type.BROWSE)
public ResponseEntity<Object> publicGetMxweb(HttpServletRequest request, @PathVariable String shareId, @PathVariable String fileId) {
validShare(request, shareId);
Optional<FileDocument> file = fileService.getMxweb(fileId);
return file.map(fileService::getObjectResponseEntity).orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND).body("找不到该文件"));
}

@Operation(summary = "显示缩略图")
@GetMapping("/public/s/view/thumbnail/{filename}")
@LogOperatingFun(logType = LogOperation.Type.BROWSE)
Expand Down
29 changes: 17 additions & 12 deletions src/main/java/com/jmal/clouddisk/lucene/LuceneService.java
Original file line number Diff line number Diff line change
Expand Up @@ -341,18 +341,23 @@ private String readFileContent(File file, String fileId) {
if (!file.isFile() || file.length() < 1) {
return null;
}
String type = FileTypeUtil.getType(file);
if ("pdf".equals(type)) {
return readContentService.readPdfContent(file, fileId);
}
if ("epub".equals(type)) {
return readContentService.readEpubContent(file, fileId);
}
if ("ppt".equals(type) || "pptx".equals(type)) {
return readContentService.readPPTContent(file);
}
if ("doc".equals(type) || "docx".equals(type)) {
return readContentService.readWordContent(file);
String type = FileTypeUtil.getType(file).toLowerCase();
switch (type) {
case "pdf" -> {
return readContentService.readPdfContent(file, fileId);
}
case "dwg" -> {
return readContentService.dwg2mxweb(file, fileId);
}
case "epub" -> {
return readContentService.readEpubContent(file, fileId);
}
case "ppt", "pptx" -> {
return readContentService.readPPTContent(file);
}
case "doc", "docx" -> {
return readContentService.readWordContent(file);
}
}
if (fileProperties.getSimText().contains(type)) {
String charset = UniversalDetector.detectCharset(file);
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/com/jmal/clouddisk/lucene/ReadContentService.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import cn.hutool.core.util.StrUtil;
import com.jmal.clouddisk.media.VideoProcessService;
import com.jmal.clouddisk.ocr.OcrService;
import com.jmal.clouddisk.service.Constants;
import com.jmal.clouddisk.service.impl.CommonFileService;
import com.jmal.clouddisk.util.FileContentUtil;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -54,6 +55,22 @@ public class ReadContentService {

public final VideoProcessService videoProcessService;

/**
* 将 DWG 文件转换为 MXWeb 文件
* @param file 文件
* @param fileId 文件 ID
* @return MXWeb 文件路径
*/
public String dwg2mxweb(File file, String fileId) {
String username = commonFileService.getUsernameByAbsolutePath(Path.of(file.getAbsolutePath()));
// 生成封面图像
if (StrUtil.isNotBlank(fileId)) {
String outputName = file.getName() + Constants.MXWEB_SUFFIX;
FileContentUtil.dwgConvert(file.getAbsolutePath(), videoProcessService.getVideoCacheDir(username, fileId), outputName);
}
return null;
}

public String readPdfContent(File file, String fileId) {
try (PDDocument document = Loader.loadPDF(new RandomAccessReadBufferedFile(file))) {

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/jmal/clouddisk/media/HeifUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ private static ProcessBuilder heifConvert(String filepath, String outputPath) {
return processBuilder;
}

private static StringBuilder printProcessInfo(Process process) throws IOException {
public static StringBuilder printProcessInfo(Process process) throws IOException {
StringBuilder output = new StringBuilder();
try (InputStream inputStream = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/jmal/clouddisk/service/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,6 @@ private Constants() { }

public static final int LOCAL_CHUNK_SIZE = 1024 * 1024;

public static final String MXWEB_SUFFIX = ".mxweb";

}
7 changes: 7 additions & 0 deletions src/main/java/com/jmal/clouddisk/service/IFileService.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,13 @@ public interface IFileService {
*/
Optional<FileDocument> thumbnail(String id, Boolean showCover);

/**
* 获取dwg文件对应的mxweb文件
* @param id fileId
* @return FileDocument
*/
Optional<FileDocument> getMxweb(String id);

/**
* 显示缩略图(媒体文件封面)
* @param id fileId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,10 @@ public void createFolder(UploadApiParamDTO upload) {
* @return fileId
*/
public String createFile(String username, File file, String userId, Boolean isPublic) {
if (CaffeineUtil.hasUploadFileCache(file.getAbsolutePath())) {
return null;
}
log.info("createFile");
if (CharSequenceUtil.isBlank(username)) {
return null;
}
Expand Down
35 changes: 25 additions & 10 deletions src/main/java/com/jmal/clouddisk/service/impl/FileServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.PathUtil;
Expand Down Expand Up @@ -477,7 +476,7 @@ public String imgUpload(String baseUrl, String filepath, MultipartFile file) {
if (!userService.getDisabledWebp(userLoginHolder.getUserId()) && (!"ico".equals(FileUtil.getSuffix(newFile)))) {
fileName += Constants.POINT_SUFFIX_WEBP;
}
createFile(username, newFile);
uploadFile(username, newFile);
return baseUrl + Paths.get("/file", username, filepath, fileName);
} catch (IOException e) {
throw new CommonException(ExceptionType.FAIL_UPLOAD_FILE.getCode(), ExceptionType.FAIL_UPLOAD_FILE.getMsg());
Expand Down Expand Up @@ -649,6 +648,20 @@ public Optional<FileDocument> thumbnail(String id, Boolean showCover) {
return Optional.empty();
}

@Override
public Optional<FileDocument> getMxweb(String id) {
FileDocument fileDocument = mongoTemplate.findById(id, FileDocument.class, COLLECTION_NAME);
if (fileDocument != null) {
String username = userService.getUserNameById(fileDocument.getUserId());
File file = Paths.get(videoProcessService.getVideoCacheDir(username,id), fileDocument.getName() + Constants.MXWEB_SUFFIX).toFile();
if (file.exists()) {
fileDocument.setContent(FileUtil.readBytes(file));
return Optional.of(fileDocument);
}
}
return Optional.empty();
}

@Override
public Optional<FileDocument> coverOfMedia(String id, String username) throws CommonException {
FileDocument fileDocument = getFileDocumentById(id);
Expand Down Expand Up @@ -1082,6 +1095,11 @@ public String createFile(String username, File file) {
return createFile(username, file, null, null);
}

private String uploadFile(String username, File file) {
CaffeineUtil.setUploadFileCache(file.getAbsolutePath());
return createFile(username, file, null, null);
}

@Override
public void updateFile(String username, File file) {
modifyFile(username, file);
Expand Down Expand Up @@ -1285,7 +1303,7 @@ public ResponseResult<FileIntroVO> addFile(String fileName, Boolean isFolder, St
fileIntroVO.setPath(resPath);
fileIntroVO.setIsFolder(isFolder);
fileIntroVO.setSuffix(FileUtil.extName(fileName));
String fileId = createFile(username, path.toFile());
String fileId = uploadFile(username, path.toFile());
fileIntroVO.setId(fileId);
return ResultUtil.success(fileIntroVO);
}
Expand Down Expand Up @@ -1484,7 +1502,7 @@ public ResponseResult<Object> duplicate(String fileId, String newFilename) {
// 复制文件
PathUtil.copyFile(fromFilePath, toFilePath);
// 保存文件信息
createFile(username, toFilePath.toFile());
uploadFile(username, toFilePath.toFile());
return ResultUtil.success();
}

Expand Down Expand Up @@ -1626,7 +1644,7 @@ private FileDocument getToFileDocument(UploadApiParamDTO upload, String to) {
private void saveFileDocument(FileDocument fileDocument) {
File file = getFileByFileDocument(fileDocument);
String username = userService.getUserNameById(fileDocument.getUserId());
createFile(username, file);
uploadFile(username, file);
}

private ResponseResult<Object> ossCopy(FileDocument fileDocumentFrom, FileDocument fileDocumentTo, String from, String to, boolean isMove) {
Expand Down Expand Up @@ -1718,7 +1736,7 @@ public ResponseResult<Object> upload(UploadApiParamDTO upload) throws IOExceptio
upload.setContentType(file.getContentType());
upload.setSuffix(FileUtil.extName(filename));
FileUtil.writeFromStream(file.getInputStream(), chunkFile);
createFile(upload.getUsername(), chunkFile);
uploadFile(upload.getUsername(), chunkFile);
uploadResponse.setUpload(true);
} else {
// 上传分片
Expand Down Expand Up @@ -1780,7 +1798,7 @@ public ResponseResult<Object> newFolder(UploadApiParamDTO upload) throws CommonE
if (!dir.exists()) {
FileUtil.mkdir(dir);
}
return ResultUtil.success(createFile(upload.getUsername(), dir));
return ResultUtil.success(uploadFile(upload.getUsername(), dir));
}

@Override
Expand Down Expand Up @@ -1898,12 +1916,10 @@ public void deleteOnlyDoc(String username, String currentDirectory, List<String>

@Override
public ResponseResult<Object> delete(String username, String currentDirectory, List<String> fileIds, String operator, boolean sweep) {
TimeInterval interval = new TimeInterval();
username = deleteOss(username, currentDirectory, fileIds, operator);
if (username == null) {
return ResultUtil.success();
}
log.info("deleteOss: {}ms", interval.intervalMs());
Query query = new Query();
query.addCriteria(Criteria.where("_id").in(fileIds));
List<FileDocument> fileDocuments = mongoTemplate.find(query, FileDocument.class, COLLECTION_NAME);
Expand Down Expand Up @@ -1951,7 +1967,6 @@ public ResponseResult<Object> delete(String username, String currentDirectory, L
} else {
operationTips.setSuccess(false);
}
log.info("deleteFile: {}ms", interval.intervalMs());
pushMessage(username, operationTips, Constants.OPERATION_TIPS);
return ResultUtil.success();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ public UploadResponse mergeFile(UploadApiParamDTO upload) throws IOException {
}
PathUtil.move(file, outputFile, true);
uploadResponse.setUpload(true);
CaffeineUtil.setUploadFileCache(outputFile.toFile().getAbsolutePath());
commonFileService.createFile(upload.getUsername(), outputFile.toFile(), null, null);
return uploadResponse;
}
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/com/jmal/clouddisk/util/CaffeineUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.jmal.clouddisk.oss.BucketInfo;
import com.jmal.clouddisk.webdav.MyWebdavServlet;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.nio.file.Path;
Expand All @@ -22,8 +23,14 @@
* @author jmal
*/
@Component
@Slf4j
public class CaffeineUtil {

/**
* 上传文件缓存, 用于判断文件是否刚刚上传, 避免一些重复的操作
*/
public static final Cache<String, Long> UPLOAD_FILE_CACHE = Caffeine.newBuilder().expireAfterWrite(5, TimeUnit.SECONDS).build();

/**
* 缩略图请求缓存
*/
Expand Down Expand Up @@ -268,6 +275,18 @@ public static String getOssPath(Path path) {
return null;
}

public static Boolean hasUploadFileCache(String key) {
Long uploadTime = UPLOAD_FILE_CACHE.getIfPresent(key);
if (uploadTime == null) {
return false;
}
return System.currentTimeMillis() - uploadTime > 5;
}

public static void setUploadFileCache(String key) {
UPLOAD_FILE_CACHE.put(key, System.currentTimeMillis());
}

public static Boolean hasThumbnailRequestCache(String id) {
return THUMBNAIL_REQUEST_CACHE.get(id, key -> false);
}
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/com/jmal/clouddisk/util/FFMPEGUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ public static void printSuccessInfo(ProcessBuilder processBuilder) {
* @return outputPath
*/
public static String getWaitingForResults(String outputPath, ProcessBuilder processBuilder, Process process) throws IOException, InterruptedException {
boolean finished = process.waitFor(12, TimeUnit.SECONDS);
return getWaitingForResults(outputPath, processBuilder, process, 12);
}

public static String getWaitingForResults(String outputPath, ProcessBuilder processBuilder, Process process, int waitSeconds) throws InterruptedException, IOException {
boolean finished = process.waitFor(waitSeconds, TimeUnit.SECONDS);
try {
log.debug("finished: {}", finished);
log.debug("exitValue: {}", process.exitValue());
Expand Down
Loading
Loading