瀏覽代碼

更新对视频和图片文件的处理

reghao 2 年之前
父節點
當前提交
4590b7f360
共有 27 個文件被更改,包括 445 次插入221 次删除
  1. 6 0
      dfs-store/pom.xml
  2. 12 9
      dfs-store/src/main/java/cn/reghao/dfs/store/controller/ObjectUploadController.java
  3. 2 0
      dfs-store/src/main/java/cn/reghao/dfs/store/db/mapper/VideoFileMapper.java
  4. 4 1
      dfs-store/src/main/java/cn/reghao/dfs/store/model/po/ImageFile.java
  5. 4 10
      dfs-store/src/main/java/cn/reghao/dfs/store/model/po/VideoFile.java
  6. 0 22
      dfs-store/src/main/java/cn/reghao/dfs/store/model/vo/ObjectMeta.java
  7. 29 0
      dfs-store/src/main/java/cn/reghao/dfs/store/model/vo/ObjectResult.java
  8. 34 0
      dfs-store/src/main/java/cn/reghao/dfs/store/rpc/MediaServiceImpl.java
  9. 4 3
      dfs-store/src/main/java/cn/reghao/dfs/store/service/FileStoreService.java
  10. 2 1
      dfs-store/src/main/java/cn/reghao/dfs/store/service/ObjectNameService.java
  11. 11 5
      dfs-store/src/main/java/cn/reghao/dfs/store/service/PutObjectService.java
  12. 6 4
      dfs-store/src/main/java/cn/reghao/dfs/store/task/ConvertTask.java
  13. 48 10
      dfs-store/src/main/java/cn/reghao/dfs/store/task/FileProcessor.java
  14. 89 0
      dfs-store/src/main/java/cn/reghao/dfs/store/task/ImageFileProcessor.java
  15. 0 97
      dfs-store/src/main/java/cn/reghao/dfs/store/task/ImageFileService.java
  16. 42 33
      dfs-store/src/main/java/cn/reghao/dfs/store/task/VideoFileProcessor.java
  17. 23 4
      dfs-store/src/main/java/cn/reghao/dfs/store/util/media/FFmpegWrapper.java
  18. 2 2
      dfs-store/src/main/java/cn/reghao/dfs/store/util/media/po/AudioProps.java
  19. 6 4
      dfs-store/src/main/java/cn/reghao/dfs/store/util/media/po/VideoProps.java
  20. 2 2
      dfs-store/src/main/resources/application-dev.yml
  21. 4 4
      dfs-store/src/main/resources/mapper/ImageFileMapper.xml
  22. 1 1
      dfs-store/src/main/resources/mapper/VideoFileMapper.xml
  23. 1 1
      dfs-store/src/main/resources/mapper/VideoUrlMapper.xml
  24. 48 5
      dfs-store/src/test/java/FileMetaTest.java
  25. 7 3
      dfs-store/src/test/java/FileTest.java
  26. 9 0
      oss-api/src/main/java/cn/reghao/oss/api/iface/MediaService.java
  27. 49 0
      oss-common/src/main/java/cn/reghao/oss/common/constant/UploadChannel.java

+ 6 - 0
dfs-store/pom.xml

@@ -127,6 +127,12 @@
             <version>2.12.0</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.sejda.imageio</groupId>
+            <artifactId>webp-imageio</artifactId>
+            <version>0.1.6</version>
+        </dependency>
+
         <dependency>
             <groupId>io.jsonwebtoken</groupId>
             <artifactId>jjwt</artifactId>

+ 12 - 9
dfs-store/src/main/java/cn/reghao/dfs/store/controller/ObjectUploadController.java

@@ -1,13 +1,14 @@
 package cn.reghao.dfs.store.controller;
 
 import cn.reghao.dfs.store.model.vo.ObjectProp;
+import cn.reghao.dfs.store.model.vo.ObjectResult;
 import cn.reghao.dfs.store.service.FileStoreService;
 import cn.reghao.dfs.store.service.ObjectNameService;
 import cn.reghao.dfs.store.service.PutObjectService;
+import cn.reghao.dfs.store.task.FileProcessor;
 import cn.reghao.jutil.jdk.result.WebResult;
 import cn.reghao.jutil.jdk.security.DigestUtil;
 import cn.reghao.jutil.web.ServletUtil;
-import cn.reghao.oss.common.UploadFileRet;
 import org.apache.commons.io.FileUtils;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
@@ -29,12 +30,14 @@ public class ObjectUploadController {
     private final FileStoreService fileStoreService;
     private final ObjectNameService objectNameService;
     private final PutObjectService putObjectService;
+    private FileProcessor fileProcessor;
 
     public ObjectUploadController(FileStoreService fileStoreService, ObjectNameService objectNameService,
-                                  PutObjectService putObjectService) {
+                                  PutObjectService putObjectService, FileProcessor fileProcessor) {
         this.fileStoreService = fileStoreService;
         this.objectNameService = objectNameService;
         this.putObjectService = putObjectService;
+        this.fileProcessor = fileProcessor;
     }
 
     //@PutMapping(value = "/**")
@@ -55,13 +58,12 @@ public class ObjectUploadController {
             ObjectProp objectProp = objectNameService.getObjectProp(channelId);
             String contentId = UUID.randomUUID().toString().replace("-", "");
             String originalFilename = file.getName();
-            long size = file.length();
-            File savedFile = fileStoreService.saveFile(file.getAbsolutePath(), contentId, size);
-            UploadFileRet uploadFileRet = putObjectService.putObject(objectProp, contentId, savedFile, originalFilename, sha256sum);
-
+            File savedFile = fileStoreService.saveFile(file, contentId);
+            ObjectResult objectResult = putObjectService.putObject(objectProp, contentId, savedFile, originalFilename, sha256sum);
+            fileProcessor.process(objectResult);
             // TODO PutMessageConverter 中生成的文件需要显式删除
             FileUtils.deleteQuietly(file);
-            return WebResult.success(uploadFileRet);
+            return WebResult.success(objectResult.getUploadFileRet());
         } catch (Exception e) {
             FileUtils.deleteQuietly(file);
             String errMsg = e.getMessage();
@@ -81,7 +83,8 @@ public class ObjectUploadController {
 
         ObjectProp objectProp = objectNameService.getObjectProp(channelId);
         String originalFilename = file.getOriginalFilename();
-        UploadFileRet uploadFileRet = putObjectService.putObject(objectProp, contentId, savedFile, originalFilename, sha256sum);
-        return WebResult.success(uploadFileRet);
+        ObjectResult objectResult = putObjectService.putObject(objectProp, contentId, savedFile, originalFilename, sha256sum);
+        fileProcessor.process(objectResult);
+        return WebResult.success(objectResult.getUploadFileRet());
     }
 }

+ 2 - 0
dfs-store/src/main/java/cn/reghao/dfs/store/db/mapper/VideoFileMapper.java

@@ -13,5 +13,7 @@ import java.util.List;
  */
 @Mapper
 public interface VideoFileMapper extends BaseMapper<VideoFile> {
+    void updateSetCover(VideoFile videoFile);
     List<VideoFile> findVideoFileByPage(Page page);
+    VideoFile findByVideoFileId(String videoFileId);
 }

+ 4 - 1
dfs-store/src/main/java/cn/reghao/dfs/store/model/po/ImageFile.java

@@ -20,17 +20,20 @@ public class ImageFile extends BaseObject<Integer> {
     private Integer height;
     private Boolean horizontal;
     private String originalUrl;
+    private String jpegUrl;
     private String webpUrl;
     private String thumbnailUrl;
     @Deprecated
     private String url;
 
-    public ImageFile(String imageFileId, Integer width, Integer height, Boolean horizontal, String originalUrl, String webpUrl) {
+    public ImageFile(String imageFileId, Integer width, Integer height, Boolean horizontal,
+                     String originalUrl, String jpegUrl, String webpUrl) {
         this.imageFileId = imageFileId;
         this.width = width;
         this.height = height;
         this.horizontal = horizontal;
         this.originalUrl = originalUrl;
+        this.jpegUrl = jpegUrl;
         this.webpUrl = webpUrl;
     }
 }

+ 4 - 10
dfs-store/src/main/java/cn/reghao/dfs/store/model/po/VideoFile.java

@@ -26,17 +26,11 @@ public class VideoFile extends BaseObject<Integer> {
     @Deprecated
     private String coverUrl;
 
-    public VideoFile(String videoFileId) {
+    public VideoFile(String videoFileId, String objectName, boolean horizontal, int duration) {
         this.videoFileId = videoFileId;
-        this.activate = false;
-        this.auth = true;
-    }
-
-    public VideoFile(VideoInfo videoInfo) {
-        this.videoFileId = videoInfo.getVideoId();
-        this.objectName = videoInfo.getVideoObjectName();
-        this.horizontal = videoInfo.getHorizontal();
-        this.duration = videoInfo.getDuration();
+        this.objectName = objectName;
+        this.horizontal = horizontal;
+        this.duration = duration;
         this.activate = false;
         this.auth = true;
     }

+ 0 - 22
dfs-store/src/main/java/cn/reghao/dfs/store/model/vo/ObjectMeta.java

@@ -1,22 +0,0 @@
-package cn.reghao.dfs.store.model.vo;
-
-import lombok.Getter;
-import lombok.Setter;
-
-import java.io.Serializable;
-
-/**
- * @author reghao
- * @date 2023-04-30 12:17:28
- */
-@Setter
-@Getter
-public class ObjectMeta implements Serializable {
-    private static final long serialVersionUID = 1L;
-
-    private String objectName;
-    private String objectId;
-    private String absolutePath;
-    private long size;
-    private String contentType;
-}

+ 29 - 0
dfs-store/src/main/java/cn/reghao/dfs/store/model/vo/ObjectResult.java

@@ -0,0 +1,29 @@
+package cn.reghao.dfs.store.model.vo;
+
+import cn.reghao.oss.common.UploadFileRet;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * @author reghao
+ * @date 2023-06-11 01:29:47
+ */
+@Setter
+@Getter
+public class ObjectResult {
+    private String objectName;
+    private String objectId;
+    private int fileType;
+    private String absolutePath;
+    private UploadFileRet uploadFileRet;
+
+    public ObjectResult(String objectName, String objectId, int fileType, String absolutePath, String url) {
+        this.objectName = objectName;
+        this.objectId = objectId;
+        this.fileType = fileType;
+        this.absolutePath = absolutePath;
+        this.uploadFileRet = new UploadFileRet(objectId, url);
+    }
+}

+ 34 - 0
dfs-store/src/main/java/cn/reghao/dfs/store/rpc/MediaServiceImpl.java

@@ -0,0 +1,34 @@
+package cn.reghao.dfs.store.rpc;
+
+import cn.reghao.dfs.store.db.mapper.ImageFileMapper;
+import cn.reghao.dfs.store.db.mapper.VideoFileMapper;
+import cn.reghao.dfs.store.model.po.ImageFile;
+import cn.reghao.dfs.store.model.po.VideoFile;
+import cn.reghao.oss.api.iface.MediaService;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author reghao
+ * @date 2023-06-10 16:33:09
+ */
+@DubboService
+@Service
+public class MediaServiceImpl implements MediaService {
+    private final ImageFileMapper imageFileMapper;
+    private final VideoFileMapper videoFileMapper;
+
+    public MediaServiceImpl(ImageFileMapper imageFileMapper, VideoFileMapper videoFileMapper) {
+        this.imageFileMapper = imageFileMapper;
+        this.videoFileMapper = videoFileMapper;
+    }
+
+    @Override
+    public void setVideoCover(String videoFileId, String coverFileId) {
+        VideoFile videoFile = videoFileMapper.findByVideoFileId(videoFileId);
+        ImageFile imageFile = imageFileMapper.findByImageFileId(coverFileId);
+
+        videoFile.setCoverUrl(imageFile.getWebpUrl());
+        videoFileMapper.updateSetCover(videoFile);
+    }
+}

+ 4 - 3
dfs-store/src/main/java/cn/reghao/dfs/store/service/FileStoreService.java

@@ -72,14 +72,14 @@ public class FileStoreService {
         return file;
     }
 
-    public File saveFile(String srcPath, String contentId, long size) throws IOException {
-        String absolutePath = genFilePath(contentId, size);
+    public File saveFile(File srcFile, String contentId) throws IOException {
+        String absolutePath = genFilePath(contentId, srcFile.length());
         File file = new File(absolutePath);
         if (file.exists()) {
             throw new IOException(absolutePath + " exist");
         }
 
-        Files.move(Path.of(srcPath), Path.of(absolutePath), StandardCopyOption.REPLACE_EXISTING);
+        Files.move(Path.of(srcFile.getAbsolutePath()), Path.of(absolutePath), StandardCopyOption.REPLACE_EXISTING);
         return file;
     }
 
@@ -94,6 +94,7 @@ public class FileStoreService {
         return file;
     }
 
+    @Deprecated
     public void saveFile(InputStream inputStream, String absolutePath) throws IOException {
         File file = new File(absolutePath);
         if (file.exists()) {

+ 2 - 1
dfs-store/src/main/java/cn/reghao/dfs/store/service/ObjectNameService.java

@@ -42,7 +42,8 @@ public class ObjectNameService {
 
         FileMeta fileMeta = objectRepository.getByObjectName(objectPrefix);
         if (fileMeta == null) {
-            throw new Exception("objectPrefix 不合法");
+            String errMsg = String.format("objectPrefix %s 不合法", objectPrefix);
+            throw new Exception(errMsg);
         }
 
         String pid = fileMeta.getObjectId();

+ 11 - 5
dfs-store/src/main/java/cn/reghao/dfs/store/service/PutObjectService.java

@@ -5,9 +5,9 @@ import cn.reghao.dfs.store.db.repository.ObjectRepository;
 import cn.reghao.dfs.store.model.po.DataBlock;
 import cn.reghao.dfs.store.model.po.FileMeta;
 import cn.reghao.dfs.store.model.vo.ObjectProp;
+import cn.reghao.dfs.store.model.vo.ObjectResult;
 import cn.reghao.jutil.jdk.security.DigestUtil;
 import cn.reghao.jutil.jdk.shell.Shell;
-import cn.reghao.oss.common.UploadFileRet;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.io.FileUtils;
 import org.springframework.stereotype.Service;
@@ -27,13 +27,14 @@ public class PutObjectService {
     private final FileStoreService fileStoreService;
     private final String domain;
 
-    public PutObjectService(ObjectRepository objectRepository, FileStoreService fileStoreService, OssProperties ossProperties) {
+    public PutObjectService(ObjectRepository objectRepository, FileStoreService fileStoreService,
+                            OssProperties ossProperties) {
         this.objectRepository = objectRepository;
         this.fileStoreService = fileStoreService;
         this.domain = ossProperties.getDomain();
     }
 
-    public UploadFileRet putObject(ObjectProp objectProp, String contentId, File savedFile, String originalFilename, String sha256sum) {
+    public ObjectResult putObject(ObjectProp objectProp, String contentId, File savedFile, String originalFilename, String sha256sum) {
         String pid = objectProp.getPid();
         String objectName = objectProp.getObjectName();
         FileMeta fileMeta = objectRepository.getBySha256sum(sha256sum);
@@ -43,7 +44,7 @@ public class PutObjectService {
 
             String objectId = objectRepository.getByObjectName(objectName).getObjectId();
             String url = String.format("https://%s/%s", domain, objectName);
-            return new UploadFileRet(objectId, url);
+            return new ObjectResult(objectName, objectId, 1, "", url);
         } else {
             String savedPath = savedFile.getAbsolutePath();
             long size = savedFile.length();
@@ -60,7 +61,7 @@ public class PutObjectService {
             objectRepository.saveObject(fileMeta, list);
 
             String url = String.format("https://%s/%s", domain, objectName);
-            return new UploadFileRet(objectId, url);
+            return new ObjectResult(objectName, objectId, fileType, savedPath, url);
         }
     }
 
@@ -75,6 +76,11 @@ public class PutObjectService {
                 String contentId = "";
                 File savedFile = fileStoreService.saveFile(bytes, contentId);
                 String filename = "";
+
+                String objectId = "";
+                String savedPath = savedFile.getAbsolutePath();
+                String contentType = getMediaType(savedPath);
+                int fileType = getFileType(contentType);
             }
         } catch (Exception e) {
             e.printStackTrace();

+ 6 - 4
dfs-store/src/main/java/cn/reghao/dfs/store/task/ConvertTask.java

@@ -40,10 +40,8 @@ public class ConvertTask implements Runnable {
             File destFile = new File(destPath);
             MediaProps mediaProps = FFmpegWrapper.getMediaProps(destPath);
             VideoProps videoProps = mediaProps.getVideoProps();
-            videoProps.getCodedWidth();
-            videoProps.getCodedHeight();
-            int width = (int) videoProps.getCodedWidth();
-            int height = (int) videoProps.getCodedHeight();
+            int width = videoProps.getCodedWidth().intValue();
+            int height = videoProps.getCodedHeight().intValue();
 
             MediaResolution mediaResolution = MediaQuality.getQuality(width, height);
             VideoUrl videoUrl = new VideoUrl(videoFileId, objectName, VideoUrlType.mp4.name(), url, mediaResolution);
@@ -53,4 +51,8 @@ public class ConvertTask implements Runnable {
             e.printStackTrace();
         }
     }
+
+    VideoUrl getConvertedVideoUrl() {
+        return null;
+    }
 }

+ 48 - 10
dfs-store/src/main/java/cn/reghao/dfs/store/task/FileProcessor.java

@@ -1,23 +1,61 @@
 package cn.reghao.dfs.store.task;
 
-import cn.reghao.dfs.store.model.po.ImageFile;
-import cn.reghao.dfs.store.model.po.VideoFile;
+import cn.reghao.dfs.store.model.vo.ObjectResult;
+import cn.reghao.jutil.jdk.thread.ThreadPoolWrapper;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.ExecutorService;
 
 /**
  * @author reghao
  * @date 2023-05-22 18:11:03
  */
 @Slf4j
+@Service
 public class FileProcessor {
-    public void process(String absolutePath, int fileType) {
-        log.info("处理 {} 类型的文件", fileType);
-        if (fileType == 1001) {
-            ImageFile imageFile = new ImageFile();
-        } else if (fileType == 1002) {
-            VideoFile videoFile = new VideoFile();
-        } else if (fileType == 1003) {
-        } else if (fileType == 1004) {
+    private final ExecutorService threadPool = ThreadPoolWrapper.threadPool("file-processor", 10);
+    private final ImageFileProcessor imageFileProcessor;
+    private final VideoFileProcessor videoFileProcessor;
+
+    public FileProcessor(ImageFileProcessor imageFileProcessor, VideoFileProcessor videoFileProcessor) {
+        this.imageFileProcessor = imageFileProcessor;
+        this.videoFileProcessor = videoFileProcessor;
+    }
+
+    public void process(ObjectResult objectResult) {
+        String objectName = objectResult.getObjectName();
+        String objectId = objectResult.getObjectId();
+        int fileType = objectResult.getFileType();
+        String absolutePath = objectResult.getAbsolutePath();
+        switch (fileType) {
+            case 1001:
+                imageFileProcessor.process(objectName, objectId, absolutePath);
+                break;
+            case 1002:
+                videoFileProcessor.process(objectName, objectId, absolutePath);
+                break;
+            case 1003:
+                break;
+            case 1004:
+                break;
+            default:
+        }
+    }
+
+    public void process(String objectName, String objectId, int fileType, String absolutePath) {
+        switch (fileType) {
+            case 1001:
+                imageFileProcessor.process(objectName, objectId, absolutePath);
+                break;
+            case 1002:
+                videoFileProcessor.process(objectName, objectId, absolutePath);
+                break;
+            case 1003:
+                break;
+            case 1004:
+                break;
+            default:
         }
     }
 }

+ 89 - 0
dfs-store/src/main/java/cn/reghao/dfs/store/task/ImageFileProcessor.java

@@ -0,0 +1,89 @@
+package cn.reghao.dfs.store.task;
+
+import cn.reghao.dfs.store.model.vo.ObjectProp;
+import cn.reghao.dfs.store.model.vo.ObjectResult;
+import cn.reghao.dfs.store.service.FileStoreService;
+import cn.reghao.dfs.store.service.ObjectNameService;
+import cn.reghao.dfs.store.service.PutObjectService;
+import cn.reghao.jutil.jdk.security.DigestUtil;
+import cn.reghao.dfs.store.db.mapper.ImageFileMapper;
+import cn.reghao.dfs.store.model.po.ImageFile;
+import cn.reghao.dfs.store.util.media.ImageOps;
+import cn.reghao.oss.common.constant.UploadChannel;
+import org.springframework.stereotype.Service;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.util.UUID;
+
+/**
+ * @author reghao
+ * @date 2023-06-11 01:29:47
+ */
+@Service
+public class ImageFileProcessor {
+    private final ImageFileMapper imageFileMapper;
+    private final FileStoreService fileStoreService;
+    private final ObjectNameService objectNameService;
+    private final PutObjectService putObjectService;
+
+    public ImageFileProcessor(ImageFileMapper imageFileMapper, FileStoreService fileStoreService,
+                              ObjectNameService objectNameService, PutObjectService putObjectService) {
+        this.imageFileMapper = imageFileMapper;
+        this.fileStoreService = fileStoreService;
+        this.objectNameService = objectNameService;
+        this.putObjectService = putObjectService;
+    }
+
+    public void process(String objectName, String objectId, String absolutePath) {
+        try {
+            String format = ImageOps.getFormat(new File(absolutePath));
+            String jpegUrl;
+            String webpUrl;
+            if (format == null) {
+                jpegUrl = getJpegUrl(absolutePath);
+                webpUrl = getWebpUrl(absolutePath);
+            } else if (format.equalsIgnoreCase("jpg") || format.equalsIgnoreCase("jpeg")) {
+                jpegUrl = String.format("//oss.reghao.cn/%s", objectName);
+                webpUrl = getWebpUrl(absolutePath);
+            } else if (format.equalsIgnoreCase("webp")) {
+                jpegUrl = getJpegUrl(absolutePath);
+                webpUrl = String.format("//oss.reghao.cn/%s", objectName);
+            } else {
+                jpegUrl = getJpegUrl(absolutePath);
+                webpUrl = getWebpUrl(absolutePath);
+            }
+
+            ImageOps.Size size = ImageOps.info(new File(absolutePath));
+            boolean horizontal = size.getWidth() > size.getHeight();
+            String originalUrl = String.format("//oss.reghao.cn/%s", objectName);
+            ImageFile imageFile =
+                    new ImageFile(objectId, size.getWidth(), size.getHeight(), horizontal, originalUrl, jpegUrl, webpUrl);
+            imageFileMapper.save(imageFile);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private String getJpegUrl(String originalPath) throws Exception {
+        byte[] bytes = ImageOps.convert2jpg(new File(originalPath));
+        return saveImage(bytes);
+    }
+
+    private String getWebpUrl(String originalPath) throws Exception {
+        BufferedImage bi = ImageIO.read(new File(originalPath));
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ImageIO.write(bi, "webp", baos);
+        return saveImage(baos.toByteArray());
+    }
+
+    private String saveImage(byte[] bytes) throws Exception {
+        ObjectProp objectProp = objectNameService.getObjectProp(UploadChannel.cover.getCode());
+        String contentId = UUID.randomUUID().toString().replace("-", "");
+        File savedFile = fileStoreService.saveFile(bytes, contentId);
+        String sha256sum = DigestUtil.sha256sum(savedFile.getAbsolutePath());
+        ObjectResult objectResult = putObjectService.putObject(objectProp, contentId, savedFile, "", sha256sum);
+        return objectResult.getUploadFileRet().getUrl();
+    }
+}

+ 0 - 97
dfs-store/src/main/java/cn/reghao/dfs/store/task/ImageFileService.java

@@ -1,97 +0,0 @@
-package cn.reghao.dfs.store.task;
-
-import cn.reghao.oss.api.dto.ImageFileRet;
-import cn.reghao.dfs.store.db.mapper.ImageFileMapper;
-import cn.reghao.dfs.store.model.po.ImageFile;
-import cn.reghao.dfs.store.util.StringUtil;
-import cn.reghao.dfs.store.util.media.ImageOps;
-import cn.reghao.jutil.jdk.exception.ExceptionUtil;
-import cn.reghao.jutil.tool.id.IdGenerator;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.io.FileUtils;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.multipart.MultipartFile;
-
-import javax.imageio.ImageIO;
-import java.awt.image.BufferedImage;
-import java.io.*;
-import java.security.NoSuchAlgorithmException;
-import java.util.UUID;
-
-/**
- * @author reghao
- * @date 2021-08-04 17:29:47
- */
-@Slf4j
-@Service
-public class ImageFileService {
-    private final ImageFileMapper imageFileMapper;
-    private final IdGenerator idGenerator;
-
-    public ImageFileService(ImageFileMapper imageFileMapper) {
-        this.imageFileMapper = imageFileMapper;
-        this.idGenerator = new IdGenerator("image-file-id");
-    }
-
-    @Transactional(rollbackFor = Exception.class)
-    public synchronized ImageFileRet putFile(MultipartFile multipartFile, String keyPrefix) throws Exception {
-        String contentType = multipartFile.getContentType();
-        String filename = multipartFile.getOriginalFilename();
-        String suffix = StringUtil.getSuffix(filename);
-        byte[] bytes = multipartFile.getBytes();
-
-        String originalUrl = putImageFile(keyPrefix, bytes, suffix);
-        String webpUrl = getWebpUrl(bytes, keyPrefix);
-        if (webpUrl == null) {
-            throw new Exception("webp 图片生成失败");
-        }
-
-        ImageOps.Size size = ImageOps.info(new ByteArrayInputStream(bytes));
-        boolean horizontal = size.getWidth() > size.getHeight();
-        String imageFileId = idGenerator.stringId();
-        ImageFile imageFile = new ImageFile(imageFileId, size.getWidth(), size.getHeight(), horizontal, originalUrl, webpUrl);
-        imageFileMapper.save(imageFile);
-        return new ImageFileRet(imageFileId, webpUrl);
-    }
-
-    private String getWebpUrl(byte[] bytes, String keyPrefix) {
-        try {
-            BufferedImage bi = ImageIO.read(new ByteArrayInputStream(bytes));
-            ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            ImageIO.write(bi, "webp", baos);
-            String contentType = "image/webp";
-            return putImageFile(keyPrefix, baos.toByteArray(), "webp");
-        } catch (Exception e) {
-            String stackTrace = ExceptionUtil.stackTrace(e);
-            log.error("{}", stackTrace);
-        }
-
-        return null;
-    }
-
-    private String putImageFile(String keyPrefix, byte[] bytes, String suffix) throws NoSuchAlgorithmException, IOException {
-        String imageId = idGenerator.stringId();
-        String objectKey = String.format("%s%s.%s", keyPrefix, imageId, suffix);
-        String tmpPath = "/opt/tmp/tomcat/" + UUID.randomUUID().toString().replace("-", "");
-        saveFile(tmpPath, bytes);
-        File file = new File(tmpPath);
-        return String.format("//oss.reghao.cn/%s", objectKey);
-    }
-
-    private void saveFile(String absolutePath, byte[] bytes) throws IOException {
-        File file = new File(absolutePath);
-        if (file.exists()) {
-            return;
-        }
-
-        File parentDir = file.getParentFile();
-        if (!parentDir.exists()) {
-            FileUtils.forceMkdir(parentDir);
-        }
-
-        FileOutputStream fos = new FileOutputStream(file);
-        fos.write(bytes);
-        fos.close();
-    }
-}

+ 42 - 33
dfs-store/src/main/java/cn/reghao/dfs/store/task/VideoFileProcessor.java

@@ -1,7 +1,7 @@
 package cn.reghao.dfs.store.task;
 
-import cn.reghao.oss.api.dto.VideoInfo;
-import cn.reghao.oss.api.dto.VideoUrlDto;
+import cn.reghao.dfs.store.util.media.po.AudioProps;
+import cn.reghao.dfs.store.util.media.po.VideoProps;
 import cn.reghao.oss.api.dto.VideoUrlType;
 import cn.reghao.dfs.store.config.OssProperties;
 import cn.reghao.dfs.store.db.mapper.VideoFileMapper;
@@ -13,9 +13,9 @@ import cn.reghao.dfs.store.util.media.MediaQuality;
 import cn.reghao.dfs.store.util.media.MediaResolution;
 import cn.reghao.dfs.store.util.media.po.MediaProps;
 import cn.reghao.jutil.jdk.thread.ThreadPoolWrapper;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
-import java.util.List;
 import java.util.UUID;
 import java.util.concurrent.ExecutorService;
 
@@ -23,6 +23,7 @@ import java.util.concurrent.ExecutorService;
  * @author reghao
  * @date 2023-01-11 10:40:17
  */
+@Slf4j
 @Service
 public class VideoFileProcessor {
     private final VideoFileMapper videoFileMapper;
@@ -36,39 +37,47 @@ public class VideoFileProcessor {
         this.endpoint = ossProperties.getDomain();
     }
 
-    public void setVideoInfo(VideoInfo videoInfo) {
-        String videoFileId = videoInfo.getVideoId();
-        String videoObjectName = videoInfo.getVideoObjectName();
-        int width = videoInfo.getWidth();
-        int height = videoInfo.getHeight();
-        String url = String.format("%s/%s", endpoint, videoObjectName);
+    public void process(String objectName, String objectId, String absolutePath) {
+        MediaProps mediaProps = FFmpegWrapper.getMediaProps(absolutePath);
+        if (mediaProps == null) {
+            log.info("{} 的 FFmpeg 媒体信息为 null", objectName);
+            return;
+        }
+
+        VideoProps videoProps = mediaProps.getVideoProps();
+        if (videoProps == null) {
+            log.info("{} 的 FFmpeg 视频信息为 null", objectName);
+            return;
+        }
+
+        String videoFileId = objectId;
+        int width = videoProps.getCodedWidth().intValue();
+        int height = videoProps.getCodedHeight().intValue();
+        boolean horizontal = width>height;
+        int duration = videoProps.getDuration().intValue();
+        String url = String.format("%s/%s", endpoint, objectName);
 
-        VideoFile videoFile = new VideoFile(videoInfo);
+        VideoFile videoFile = new VideoFile(videoFileId, objectName, horizontal, duration);
         videoFileMapper.save(videoFile);
-        try {
-            String destPath = "/opt/tmp/tomcat/" + UUID.randomUUID().toString().replace("-", "");
-            MediaProps mediaProps = FFmpegWrapper.getMediaProps(destPath);
-            if (mediaProps != null && mediaProps.getAudioProps() != null && mediaProps.getVideoProps() != null) {
-                String audioCodec = mediaProps.getAudioProps().getCodecName();
-                String videoCodec = mediaProps.getVideoProps().getCodecName();
-                if ("aac".equals(audioCodec) && "h264".equals(videoCodec)) {
-                    MediaResolution mediaResolution = MediaQuality.getQuality(width, height);
-                    VideoUrl videoUrl = new VideoUrl(videoFileId, videoObjectName, VideoUrlType.mp4.name(), url, mediaResolution);
-                    videoUrlMapper.save(videoUrl);
-                } else {
-                    ConvertTask convertTask = new ConvertTask(videoFileId, destPath, endpoint, videoUrlMapper);
-                    threadPool.submit(convertTask);
-                }
-            } else {
-                ConvertTask convertTask = new ConvertTask(videoFileId, destPath, endpoint, videoUrlMapper);
-                threadPool.submit(convertTask);
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
+
+        AudioProps audioProps = mediaProps.getAudioProps();
+        if (audioProps == null) {
+            log.info("{} 的 FFmpeg 视频信息为 null", objectName);
+            return;
+        }
+
+        String audioCodec = mediaProps.getAudioProps().getCodecName();
+        String videoCodec = mediaProps.getVideoProps().getCodecName();
+        if ("aac".equals(audioCodec) && "h264".equals(videoCodec)) {
+            MediaResolution mediaResolution = MediaQuality.getQuality(width, height);
+            VideoUrl videoUrl = new VideoUrl(videoFileId, objectName, VideoUrlType.mp4.name(), url, mediaResolution);
+            videoUrlMapper.save(videoUrl);
+            return;
         }
-    }
 
-    public List<VideoUrlDto> getVideoUrls(String videoFileId, String urlType) {
-        return videoUrlMapper.findVideoUrls(videoFileId, urlType);
+        String destPath = "/opt/tmp/tomcat/" + UUID.randomUUID().toString().replace("-", "");
+        ConvertTask convertTask = new ConvertTask(videoFileId, destPath, endpoint, videoUrlMapper);
+        log.info("添加视频格式转码任务");
+        //threadPool.submit(convertTask);
     }
 }

+ 23 - 4
dfs-store/src/main/java/cn/reghao/dfs/store/util/media/FFmpegWrapper.java

@@ -34,7 +34,15 @@ public class FFmpegWrapper {
                 if (codecType.equals("audio")) {
                     String codecName = jsonObject1.get("codec_name").getAsString();
                     String codecTagString = jsonObject1.get("codec_tag_string").getAsString();
-                    double bitRate = jsonObject1.get("bit_rate").getAsDouble();
+
+                    JsonElement bitRateElement = jsonObject1.get("bit_rate");
+                    double bitRate;
+                    if (bitRateElement == null) {
+                        bitRate = 0.0;
+                    } else {
+                        bitRate = bitRateElement.getAsDouble();
+                    }
+
                     JsonElement durationElement = jsonObject1.get("duration");
                     double duration;
                     if (durationElement == null) {
@@ -69,10 +77,21 @@ public class FFmpegWrapper {
                 }
             }
 
+            if (videoProps == null) {
+                return null;
+            }
+
             JsonObject format = jsonObject.get("format").getAsJsonObject();
-            double duration = format.get("duration").getAsDouble();
-            double size = format.get("size").getAsDouble();
-            double bitRate = format.get("bit_rate").getAsDouble();
+            if (format.get("duration") != null) {
+                Double duration = format.get("duration").getAsDouble();
+                videoProps.setDuration(duration);
+            }
+
+            Long size = format.get("size").getAsLong();
+            if (format.get("bit_rate") != null) {
+                Double bitRate = format.get("bit_rate").getAsDouble();
+                videoProps.setBitRate(bitRate);
+            }
 
             MediaProps mediaProps = new MediaProps(audioProps, videoProps);
             JsonElement tagsElement = format.get("tags");

+ 2 - 2
dfs-store/src/main/java/cn/reghao/dfs/store/util/media/po/AudioProps.java

@@ -12,6 +12,6 @@ import lombok.Getter;
 public class AudioProps {
     private String codecName;
     private String codecTagString;
-    private double bitRate;
-    private double duration;
+    private Double bitRate;
+    private Double duration;
 }

+ 6 - 4
dfs-store/src/main/java/cn/reghao/dfs/store/util/media/po/VideoProps.java

@@ -2,18 +2,20 @@ package cn.reghao.dfs.store.util.media.po;
 
 import lombok.AllArgsConstructor;
 import lombok.Getter;
+import lombok.Setter;
 
 /**
  * @author reghao
  * @date 2023-03-28 10:07:53
  */
 @AllArgsConstructor
+@Setter
 @Getter
 public class VideoProps {
     private String codecName;
     private String codecTagString;
-    private double bitRate;
-    private double duration;
-    private double codedWidth;
-    private double codedHeight;
+    private Double bitRate;
+    private Double duration;
+    private Double codedWidth;
+    private Double codedHeight;
 }

+ 2 - 2
dfs-store/src/main/resources/application-dev.yml

@@ -8,10 +8,10 @@ spring:
     port: 6379
     password: Dev@123456
   datasource:
-    url: jdbc:mysql://localhost:3306/reghao_oss_rdb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8
+    url: jdbc:mysql://127.0.0.1:3306/reghao_oss_rdb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8
     username: dev
     password: Dev@123456
 oss:
   domain: oss.reghao.cn
   mountedDirs:
-    - /opt/oss/disk/00b989fc-991b-4d4e-959e-9b6e19299b72/
+    - /opt/oss/disk/13f654c8-af87-4710-aac9-7aa086c99aec/

+ 4 - 4
dfs-store/src/main/resources/mapper/ImageFileMapper.xml

@@ -4,16 +4,16 @@
 <mapper namespace="cn.reghao.dfs.store.db.mapper.ImageFileMapper">
     <insert id="save" useGeneratedKeys="true" keyProperty="id">
         insert into image_file
-        (`id`,`deleted`,`create_time`,`update_time`,`image_file_id`,`width`,`height`,`horizontal`,`original_url`,`webp_url`,`thumbnail_url`)
+        (`id`,`deleted`,`create_time`,`update_time`,`image_file_id`,`width`,`height`,`horizontal`,`original_url`,`jpeg_url`,`webp_url`,`thumbnail_url`)
         values 
-        (#{id},#{deleted},#{createTime},#{updateTime},#{imageFileId},#{width},#{height},#{horizontal},#{originalUrl},#{webpUrl},#{thumbnailUrl})
+        (#{id},#{deleted},#{createTime},#{updateTime},#{imageFileId},#{width},#{height},#{horizontal},#{originalUrl},#{jpegUrl},#{webpUrl},#{thumbnailUrl})
     </insert>
     <insert id="saveAll" useGeneratedKeys="true" keyProperty="id">
         insert into image_file
-        (`id`,`deleted`,`create_time`,`update_time`,`image_file_id`,`width`,`height`,`horizontal`,`original_url`,`webp_url`,`thumbnail_url`)
+        (`id`,`deleted`,`create_time`,`update_time`,`image_file_id`,`width`,`height`,`horizontal`,`original_url`,`jpeg_url`,`webp_url`,`thumbnail_url`)
         values
         <foreach collection="list" item="item" index="index" separator=",">
-            (#{item.id},#{item.deleted},#{item.createTime},#{item.updateTime},#{item.imageFileId},#{item.width},#{item.height},#{item.horizontal},#{item.originalUrl},#{item.webpUrl},#{item.thumbnailUrl})
+            (#{item.id},#{item.deleted},#{item.createTime},#{item.updateTime},#{item.imageFileId},#{item.width},#{item.height},#{item.horizontal},#{item.originalUrl},#{item.jpegUrl},#{item.webpUrl},#{item.thumbnailUrl})
         </foreach>
     </insert>
 

+ 1 - 1
dfs-store/src/main/resources/mapper/VideoFileMapper.xml

@@ -6,7 +6,7 @@
         insert into video_file
         (`id`,`deleted`,`create_time`,`update_time`,`video_file_id`,`object_name`,`horizontal`,`duration`,`activate`,`auth`)
         values 
-        (#{id},#{deleted},#{createTime},#{updateTime},#{videoFileId},#{objectProp},#{horizontal},#{duration},#{activate},#{auth})
+        (#{id},#{deleted},#{createTime},#{updateTime},#{videoFileId},#{objectName},#{horizontal},#{duration},#{activate},#{auth})
     </insert>
 
     <select id="findAll" resultType="cn.reghao.dfs.store.model.po.VideoFile">

+ 1 - 1
dfs-store/src/main/resources/mapper/VideoUrlMapper.xml

@@ -6,7 +6,7 @@
         insert into video_url
         (`video_file_id`,`object_name`,`url_type`,`width`,`height`,`quality`,`url`)
         values
-        (#{videoFileId},#{objectProp},#{urlType},#{width},#{height},#{quality},#{url})
+        (#{videoFileId},#{objectName},#{urlType},#{width},#{height},#{quality},#{url})
     </insert>
 
     <select id="findVideoUrls" resultType="cn.reghao.oss.api.dto.VideoUrlDto">

+ 48 - 5
dfs-store/src/test/java/FileMetaTest.java

@@ -1,8 +1,11 @@
 import cn.reghao.dfs.store.DfsStoreApplication;
 import cn.reghao.dfs.store.db.mapper.FileMetaMapper;
+import cn.reghao.dfs.store.db.repository.ObjectRepository;
 import cn.reghao.dfs.store.model.po.FileMeta;
 import cn.reghao.jutil.jdk.db.Page;
 import cn.reghao.jutil.jdk.security.DigestUtil;
+import cn.reghao.jutil.jdk.thread.ThreadPoolWrapper;
+import cn.reghao.oss.api.dto.ObjectMeta;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.io.FileUtils;
 import org.junit.Test;
@@ -21,6 +24,7 @@ import java.nio.file.Path;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.security.NoSuchAlgorithmException;
 import java.util.List;
+import java.util.concurrent.ExecutorService;
 
 /**
  * @author reghao
@@ -107,19 +111,58 @@ public class FileMetaTest {
             FileMeta fileMeta = fileMetaMapper.findBySha256sum(sha256sum);
             if (fileMeta != null) {
                 FileUtils.deleteQuietly(new File(absolutePath));
+                log.info("{} 删除 {} -> {}", Thread.currentThread().getName(), total++, absolutePath);
             } else {
-                log.info("{} 在 db 中不存在", absolutePath);
+                //log.info("{} 在 db 中不存在", absolutePath);
             }
         } catch (IOException | NoSuchAlgorithmException e) {
             e.printStackTrace();
         }
     }
 
+    ExecutorService threadPool = ThreadPoolWrapper.threadPool("delete-pool", 10);
+    int total = 1;
     @Test
-    public void deleteFile() throws IOException {
-        String baseDir = "/home/reghao/mnt/porn/0.已完成";
-        baseDir = "/run/media/reghao/7c43343d-c1e2-4e68-bc18-89bd3f61b0c8/spider/porn/";
+    public void deleteFile() throws IOException, InterruptedException {
+        String baseDir = "/home/reghao/mnt1/spider/bili/img/vidcover";
+        //baseDir = "/run/media/reghao/7c43343d-c1e2-4e68-bc18-89bd3f61b0c8/cover";
+        //baseDir = "/home/reghao/mnt1/spider/bili/img/avatar";
         Path path = Path.of(baseDir);
-        walkDir(path);
+        //walkDir(path);
+
+        threadPool.submit(new Task("/home/reghao/mnt1/spider/bili/img/avatar"));
+        threadPool.submit(new Task("/run/media/reghao/7c43343d-c1e2-4e68-bc18-89bd3f61b0c8/cover"));
+        threadPool.submit(new Task("/run/media/reghao/7c43343d-c1e2-4e68-bc18-89bd3f61b0c8/avatar"));
+
+        Thread.sleep(3600_000*24*7);
+    }
+
+    class Task implements Runnable {
+        private final String baseDir;
+
+        public Task(String baseDir) {
+            this.baseDir = baseDir;
+        }
+
+        @Override
+        public void run() {
+            Path path = Path.of(baseDir);
+            try {
+                walkDir(path);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Autowired
+    ObjectRepository objectRepository;
+    @Test
+    public void test1() {
+        String objectName = "image/cover/0d4f4b07ca894bdb97cdf7d46a89b5a7";
+        //objectName = "video/playback/57ddc192e2cb4461912beb19316943bb";
+
+        ObjectMeta objectMeta = objectRepository.getObjectMeta(objectName);
+        String contentType = objectMeta.getContentType();
     }
 }

+ 7 - 3
dfs-store/src/test/java/FileTest.java

@@ -73,8 +73,8 @@ public class FileTest {
 
         String audioCodec = audioProps.getCodecName();
         String videoCodec = videoProps.getCodecName();
-        int width = (int) videoProps.getCodedWidth();
-        int height = (int) videoProps.getCodedHeight();
+        int width = videoProps.getCodedWidth().intValue();
+        int height = videoProps.getCodedHeight().intValue();
         if ("aac".equals(audioCodec) && "h264".equals(videoCodec)) {
             MediaResolution mediaResolution = MediaQuality.getQuality(width, height);
         } else {
@@ -103,6 +103,10 @@ public class FileTest {
     public void test22() throws IOException {
         String baseDir = "/home/reghao/mnt/porn/1.待发布/13996.反差婊系列/p/";
         Path path = Path.of(baseDir);
-        walkDir(path);
+        //walkDir(path);
+
+        String filePath = "/run/media/reghao/a4d27bae-50d7-4d3b-9e55-7641f52277e5/1ren.tv/2/1125457010/rtmp_1664557007.flv";
+        MediaProps mediaProps = FFmpegWrapper.getMediaProps(filePath);
+        System.out.println();
     }
 }

+ 9 - 0
oss-api/src/main/java/cn/reghao/oss/api/iface/MediaService.java

@@ -0,0 +1,9 @@
+package cn.reghao.oss.api.iface;
+
+/**
+ * @author reghao
+ * @date 2023-06-10 16:32:38
+ */
+public interface MediaService {
+    void setVideoCover(String videoFileId, String coverFileId);
+}

+ 49 - 0
oss-common/src/main/java/cn/reghao/oss/common/constant/UploadChannel.java

@@ -0,0 +1,49 @@
+package cn.reghao.oss.common.constant;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author reghao
+ * @date 2023-05-23 10:43:25
+ */
+public enum UploadChannel {
+    // 网盘上传
+    disk(1, "file/"),
+    // 视频上传
+    video(2, "video/playback/"),
+    // 视频封面上传
+    cover(3, "image/cover/"),
+    // 用户头像上传
+    avatar(4, "image/avatar/"),
+    // 用户状态照片上传
+    photo(5, "image/photo/"),
+    // 音频上传
+    audio(6, "audio/playback/");
+
+    private final int code;
+    private final String prefix;
+    UploadChannel(int code, String prefix) {
+        this.code = code;
+        this.prefix = prefix;
+    }
+
+    private static Map<Integer, String> map = new HashMap<>();
+    static {
+        for (UploadChannel channel : UploadChannel.values()) {
+            map.put(channel.code, channel.prefix);
+        }
+    }
+
+    public static String getPrefix(int code) {
+        return map.get(code);
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public String getPrefix() {
+        return prefix;
+    }
+}