package cn.iocoder.yudao.module.digitalcourse.service.coursemedia; import cn.hutool.core.io.FileUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.*; 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 cn.iocoder.yudao.module.infra.api.config.ConfigApi; import cn.iocoder.yudao.module.infra.api.file.FileApi; import com.alibaba.fastjson.JSON; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; 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.io.*; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import static cn.iocoder.yudao.module.digitalcourse.enums.ErrorCodeConstants.COURSE_MEDIA_NOT_EXISTS; /** * 课程媒体 Service 实现类 * * @author 芋道源码 */ @Service @Validated @Slf4j public class CourseMediaServiceImpl implements CourseMediaService { @Resource private CourseMediaMapper courseMediaMapper; @Resource private CourseMediaServiceUtil courseMediaServiceUtil; @Resource private FileApi fileApi; @Override public Long createCourseMedia(CourseMediaSaveReqVO createReqVO) { // 插入 CourseMediaDO courseMedia = BeanUtils.toBean(createReqVO, CourseMediaDO.class); courseMediaMapper.insert(courseMedia); // 返回 return courseMedia.getId(); } @Override public void updateCourseMedia(CourseMediaSaveReqVO updateReqVO) { // 校验存在 validateCourseMediaExists(updateReqVO.getId()); // 更新 CourseMediaDO updateObj = BeanUtils.toBean(updateReqVO, CourseMediaDO.class); courseMediaMapper.updateById(updateObj); } @Override public void deleteCourseMedia(Long id) { // 校验存在 validateCourseMediaExists(id); // 删除 courseMediaMapper.deleteById(id); } private void validateCourseMediaExists(Long id) { if (courseMediaMapper.selectById(id) == null) { throw exception(COURSE_MEDIA_NOT_EXISTS); } } @Override public CourseMediaDO getCourseMedia(Long id) { return courseMediaMapper.selectById(id); } @Override public PageResult getCourseMediaPage(CourseMediaPageReqVO pageReqVO) { PageResult courseMediaDOPageResult = courseMediaMapper.selectPage(pageReqVO); for (CourseMediaDO courseMediaDO : courseMediaDOPageResult.getList()) { if (courseMediaDO.getStatus() == 1 || courseMediaDO.getStatus() == 0) { //视频合成中 查询排队和合成进度 Long id = courseMediaDO.getCourseId(); int pos = mediaTaskManager.getQueuePosition(id); if (pos == -1) { //不在队列中,说明已经合成完成 courseMediaDO.setStatus(3); courseMediaMapper.updateById(courseMediaDO); } if (pos == 0) { //正在合成中 String reqJson = courseMediaDO.getReqJson(); CourseMediaMegerVO courseMediaMegerVO = JSON.parseObject(reqJson, CourseMediaMegerVO.class); int size = courseMediaMegerVO.getScenes().size(); String s = configApi.getConfigValueByKey(HEYGEM_FACE2FACE) + "/temp/"; //查询s下面的文件 File folder = new File(s); int count = 0; if (folder.exists() && folder.isDirectory()) { File[] files = folder.listFiles(); if (files != null) { for (File file : files) { if (file.isFile() && file.getName().endsWith("-r.mp4")) { count++; System.out.println("匹配文件: " + file.getName()); } } } System.out.println("总计匹配 -r.mp4 文件数量: " + count); } else { System.out.println("路径不存在或不是目录"); } if (count+1>size){ courseMediaDO.setProgressVideo((count) + "/" + size); }else{ courseMediaDO.setProgressVideo((count)+"/"+size); } } courseMediaDO.setPos(pos); } } return courseMediaDOPageResult; } private static final String HEYGEM_FACE2FACE = "heygem.face2face"; @Resource private ConfigApi configApi; @Override public CommonResult megerMedia(CourseMediaMegerVO updateReqVO) { Long id = updateReqVO.getId(); CourseMediaDO courseMediaDO = courseMediaMapper.selectOne(new QueryWrapperX().lambda().eq(CourseMediaDO::getCourseId,id).in(CourseMediaDO::getStatus,0,1)); if (courseMediaDO == null){ courseMediaDO = new CourseMediaDO(); courseMediaDO.setCourseId(id); courseMediaDO.setStatus(0); courseMediaDO.setMediaType(1); courseMediaDO.setName(updateReqVO.getName()); courseMediaDO.setCourseName(updateReqVO.getName()); // courseMediaDO.setAuditVo(updateReqVO.getAuditionVo()); //将updateReqVO 转换为json字符串 courseMediaDO.setReqJson(JSON.toJSONString(updateReqVO)); courseMediaMapper.insert(courseMediaDO); }else{ return CommonResult.error(BAD_REQUEST.getCode(),"已存在合成中视频,不允许重复合成"); } updateReqVO.setCourseMediaId(courseMediaDO.getId()); //异步调用数字人视频渲染接口,开始合并 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(); CourseMediaDO courseMediaDO = courseMediaMapper.selectById(updateReqVO.getId()); if (courseMediaDO == null){ return CommonResult.error(BAD_REQUEST.getCode(),"未查询到合成视频记录"); } if (3!=courseMediaDO.getStatus()){ return CommonResult.error(BAD_REQUEST.getCode(),"只有失败状态视频允许重新合成视频"); } //异步调用数字人视频渲染接口,开始合并 Boolean success = courseMediaServiceUtil.reMegerMedia(courseMediaDO); if(success) { return CommonResult.success(true); } else { return CommonResult.error(BAD_REQUEST.getCode(),"视频重新合成失败"); } } @Override public CommonResult createSubtitles(CourseMediaSubtitlesReqVO courseMediaSubtitlesReqVO) { CourseMediaDO courseMediaDO1 = courseMediaMapper.selectOne(new QueryWrapperX().lambda().eq(CourseMediaDO::getId, courseMediaSubtitlesReqVO.getId())); if (courseMediaDO1.getSubtitlesStatus()!= null && courseMediaDO1.getSubtitlesStatus() == 1) { throw new RuntimeException("字幕生成中,请勿重复提交"); } CourseMediaDO courseMediaDO = new CourseMediaDO(); courseMediaDO.setId(courseMediaSubtitlesReqVO.getId()); courseMediaDO.setSubtitlesStatus(1); courseMediaMapper.updateById(courseMediaDO); courseMediaServiceUtil.createSubtitles(courseMediaSubtitlesReqVO); return CommonResult.success("视频字幕生成中,请稍后查看"); } @Override public CommonResult createSubtitlesVideo(CourseMediaSubtitlesReqVO courseMediaSubtitlesReqVO) { CourseMediaDO courseMediaDO1 = courseMediaMapper.selectOne(new QueryWrapperX().lambda().eq(CourseMediaDO::getId, courseMediaSubtitlesReqVO.getId()).eq(CourseMediaDO::getSubtitlesStatus, 2)); if (courseMediaDO1 == null) { return CommonResult.error(BAD_REQUEST.getCode(), "字幕文件不存在或未生成"); } CourseMediaDO courseMediaDO = new CourseMediaDO(); courseMediaDO.setCourseId(courseMediaSubtitlesReqVO.getId()); courseMediaDO.setSubtitlesAddStatus(1); courseMediaMapper.updateById(courseMediaDO); courseMediaServiceUtil.createSubtitlesVideo(courseMediaDO1); return CommonResult.success("视频添加字幕中,请稍后查看"); } @Override public void updateSubtitles(CourseMediaEditSReqVO updateReqVO) { // 校验存在 validateCourseMediaExists(updateReqVO.getId()); // 更新 CourseMediaDO updateObj = BeanUtils.toBean(updateReqVO, CourseMediaDO.class); updateObj.setSubtitlesStatus(2); courseMediaMapper.updateById(updateObj); } /** * 上传片头片尾 * @param courseMediaSubtitlesReqVO * @return */ @Override public CommonResult createTrailer(CourseMediaSubtitlesReqVO courseMediaSubtitlesReqVO) { CourseMediaDO courseMediaDO = new CourseMediaDO(); courseMediaDO.setId(courseMediaSubtitlesReqVO.getId()); courseMediaDO.setTrailer(courseMediaSubtitlesReqVO.getTrailer()); courseMediaDO.setTitles(courseMediaSubtitlesReqVO.getTitles()); int i = courseMediaMapper.updateById(courseMediaDO); if (i>0){ return CommonResult.success("片头片尾上传成功"); } return CommonResult.error(BAD_REQUEST.getCode(),"片头片尾上传失败"); } /** * 合成片头片尾视频 * @param courseMediaSubtitlesReqVO * @return */ @Override public CommonResult createCompositeVideo(CourseMediaSubtitlesReqVO courseMediaSubtitlesReqVO) { //异步合成 courseMediaServiceUtil.createCompositeVideo(courseMediaSubtitlesReqVO); return CommonResult.success("视频合成中,请稍后查看"); } }