From f75f9d9cc646d83f9d53edd4a82764fd086a3cc1 Mon Sep 17 00:00:00 2001
From: 康鲁杰 <60095866+KangLujie@users.noreply.github.com>
Date: 星期二, 08 四月 2025 08:32:55 +0800
Subject: [PATCH] 队列生成视频

---
 media_task_queue.json                                                                                                                                         |    1 
 yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/coursemedia/CourseMediaServiceImpl.java |   33 +++----
 yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/coursemedia/CourseMediaServiceUtil.java |    6 +
 yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/model/MediaTask.java                            |   21 +++++
 yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/manager/MediaTaskManager.java                   |  144 ++++++++++++++++++++++++++++++++++++
 5 files changed, 185 insertions(+), 20 deletions(-)

diff --git a/media_task_queue.json b/media_task_queue.json
new file mode 100644
index 0000000..8b735b5
--- /dev/null
+++ b/media_task_queue.json
@@ -0,0 +1 @@
+{"current":null,"queue":[]}
\ No newline at end of file
diff --git a/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/manager/MediaTaskManager.java b/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/manager/MediaTaskManager.java
new file mode 100644
index 0000000..5cfd878
--- /dev/null
+++ b/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/manager/MediaTaskManager.java
@@ -0,0 +1,144 @@
+package cn.iocoder.yudao.module.digitalcourse.manager;
+
+import cn.iocoder.yudao.module.digitalcourse.model.MediaTask;
+import cn.iocoder.yudao.module.digitalcourse.service.coursemedia.CourseMediaServiceUtil;
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.PreDestroy;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * @author kanglujie
+ * @date 2025-04-07 14:36:00
+ */
+@Component
+public class MediaTaskManager {
+
+    private final BlockingQueue<MediaTask> queue = new LinkedBlockingQueue<>();
+    private final ExecutorService executor = Executors.newSingleThreadExecutor();
+    private final ObjectMapper mapper = new ObjectMapper()
+            .registerModule(new JavaTimeModule())
+            .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+    private final Path persistPath = Paths.get("media_task_queue.json");
+    private final Path persistTempPath = Paths.get("media_task_queue_temp.json");
+
+    private final Object lock = new Object(); // 閿佸璞�
+
+    private volatile MediaTask currentTask = null;
+
+    @Resource
+    private CourseMediaServiceUtil courseMediaServiceUtil;
+
+    @PostConstruct
+    public void init() throws IOException {
+        mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
+        loadQueueFromDisk();
+        startWorker();
+    }
+
+    public int submitTask(MediaTask task) throws IOException {
+        synchronized (lock) {
+            queue.add(task);
+            persistQueue(); // 绔嬪嵆鎸佷箙鍖�
+            return queue.size();
+        }
+    }
+
+    public int getQueuePosition(Long taskId) {
+        int pos = 1;
+        if (currentTask != null && currentTask.getId().equals(taskId)) return 0;
+        for (MediaTask task : queue) {
+            if (task.getId().equals(taskId)) return pos;
+            pos++;
+        }
+        return -1;
+    }
+
+    private void startWorker() {
+        executor.submit(() -> {
+            while (true) {
+                try {
+                    currentTask = queue.take(); // 寮�濮嬪鐞�
+                    persistQueue();
+                    System.out.println("寮�濮嬪悎鎴愶細" + currentTask.getId());
+                    courseMediaServiceUtil.remoteMegerMedia(currentTask.getReq());
+                    synchronized (lock) {
+                        currentTask = null;
+                        persistQueue(); // 鎵ц瀹屽啀鎸佷箙鍖�
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    // 濡傛灉寮傚父浜嗭紝閲嶆柊鍏ラ槦
+                    if (currentTask != null) {
+                        queue.add(currentTask);
+                        currentTask = null;
+                    }
+                    persistQueue();
+                }
+            }
+        });
+    }
+
+    private void persistQueue() {
+        synchronized (lock) {
+            try {
+                QueueState state = new QueueState();
+                state.current = currentTask;
+                state.queue = new ArrayList<>(queue);
+
+                mapper.writeValue(persistTempPath.toFile(), state);
+                Files.move(persistTempPath, persistPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private void loadQueueFromDisk() {
+        synchronized (lock) {
+            if (Files.exists(persistPath)) {
+                try {
+                    QueueState state = mapper.readValue(persistPath.toFile(), QueueState.class);
+                    if (state.current != null) {
+                        queue.add(state.current);
+                    }
+                    if (state.queue != null) {
+                        queue.addAll(state.queue);
+                    }
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    @PreDestroy
+    public void shutdown() {
+        executor.shutdownNow();
+        persistQueue();
+    }
+
+    // 鍐呴儴绫荤敤浜� JSON 鏄犲皠
+    public static class QueueState {
+        public MediaTask current;
+        public List<MediaTask> queue;
+    }
+}
diff --git a/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/model/MediaTask.java b/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/model/MediaTask.java
new file mode 100644
index 0000000..7c4a522
--- /dev/null
+++ b/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/model/MediaTask.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.digitalcourse.model;
+
+/**
+ * @author kanglujie
+ * @date 2025-04-07 14:35:03
+ */
+import cn.iocoder.yudao.module.digitalcourse.controller.admin.coursemedia.vo.CourseMediaMegerVO;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class MediaTask {
+    private Long id;
+    private CourseMediaMegerVO req;
+    private LocalDateTime submitTime;
+}
diff --git a/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/coursemedia/CourseMediaServiceImpl.java b/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/coursemedia/CourseMediaServiceImpl.java
index ae687d9..18e62fc 100644
--- a/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/coursemedia/CourseMediaServiceImpl.java
+++ b/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/coursemedia/CourseMediaServiceImpl.java
@@ -1,38 +1,28 @@
 package cn.iocoder.yudao.module.digitalcourse.service.coursemedia;
 
-import cn.hutool.http.HttpRequest;
-import cn.hutool.http.HttpResponse;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
 import cn.iocoder.yudao.module.digitalcourse.controller.admin.coursemedia.vo.CourseMediaMegerVO;
 import cn.iocoder.yudao.module.digitalcourse.controller.admin.coursemedia.vo.CourseMediaPageReqVO;
 import cn.iocoder.yudao.module.digitalcourse.controller.admin.coursemedia.vo.CourseMediaSaveReqVO;
-import cn.iocoder.yudao.module.digitalcourse.controller.admin.courses.vo.AppCoursesUpdateReqVO;
 import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.coursemedia.CourseMediaDO;
 import cn.iocoder.yudao.module.digitalcourse.dal.mysql.coursemedia.CourseMediaMapper;
+import cn.iocoder.yudao.module.digitalcourse.manager.MediaTaskManager;
+import cn.iocoder.yudao.module.digitalcourse.model.MediaTask;
 import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.scheduling.annotation.Async;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 
-import java.math.BigInteger;
+import java.io.IOException;
 import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.module.digitalcourse.enums.ErrorCodeConstants.COURSE_MEDIA_NOT_EXISTS;
 
@@ -115,10 +105,17 @@
         }
         updateReqVO.setCourseMediaId(courseMediaDO.getId());
         //寮傛璋冪敤鏁板瓧浜鸿棰戞覆鏌撴帴鍙o紝寮�濮嬪悎骞�
-        courseMediaServiceUtil.remoteMegerMedia(updateReqVO);
-        return CommonResult.success(true);
+        MediaTask task = new MediaTask(id, updateReqVO, LocalDateTime.now());
+        int pos = 0;
+        try {
+            pos = mediaTaskManager.submitTask(task);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        return CommonResult.success("鍚堟垚瑙嗛鎻愪氦鎴愬姛锛屾偍鎺掑湪绗� " + (pos+1) + " 涓�");
     }
-
+    @Resource
+    private MediaTaskManager mediaTaskManager;
     @Override
     public CommonResult reMegerMedia(CourseMediaMegerVO updateReqVO) {
         Long id = updateReqVO.getId();
@@ -141,4 +138,4 @@
 
 
 
-}
\ No newline at end of file
+}
diff --git a/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/coursemedia/CourseMediaServiceUtil.java b/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/coursemedia/CourseMediaServiceUtil.java
index 749dfe0..f414166 100644
--- a/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/coursemedia/CourseMediaServiceUtil.java
+++ b/yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/coursemedia/CourseMediaServiceUtil.java
@@ -73,9 +73,11 @@
      * @param updateReqVO
      * @return
      */
-    @Async
     public void remoteMegerMedia(CourseMediaMegerVO updateReqVO) {
+        FileUtil.clean("D:/heygem_data/face2face/temp/");
         CourseMediaDO courseMediaDO = courseMediaMapper.selectById(updateReqVO.getCourseMediaId());
+        courseMediaDO.setStatus(1);
+        courseMediaMapper.updateById(courseMediaDO);
         List<AppCourseScenesMegerReqVO> scenes = updateReqVO.getScenes();
         //鑾峰彇鏁板瓧浜虹礌鏉愶紙澹伴煶銆佽棰戯級
         String entityId = null;
@@ -279,7 +281,7 @@
         byte[] bytes = FileUtil.readBytes(FileUtil.file("D:/heygem_data/face2face/temp/"+"111111.mp4"));
         String file = fileApi.createFile(bytes);
         // 濡傛灉鎴愬姛锛屾洿鏂扮姸鎬佷负1锛堟垚鍔燂級
-        courseMediaDO.setStatus(1);
+        courseMediaDO.setStatus(2);
         courseMediaDO.setPreviewUrl(file);
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         Date date = new Date();

--
Gitblit v1.9.3