diff --git a/pom.xml b/pom.xml index 22d7b2f8..5a8dc60d 100644 --- a/pom.xml +++ b/pom.xml @@ -135,7 +135,11 @@ 3.12.5 - + + org.bytedeco + javacv-platform + 1.5.6 + com.aliyun @@ -187,7 +191,7 @@ aspose-words aspose-words-22.10-jdk16 system - ${project.basedir}/src/main/resources/lib/aspose-words-22.10-jdk16.jar + ${pom.basedir}/src/main/resources/lib/aspose-words-22.10-jdk16.jar org.jsoup @@ -483,6 +487,16 @@ true + + central + https://maven.aliyun.com/repository/central + + true + + + true + + com.e-iceblue https://repo.e-iceblue.cn/repository/maven-public/ diff --git a/src/main/java/com/peanut/common/service/AsyncService.java b/src/main/java/com/peanut/common/service/AsyncService.java new file mode 100644 index 00000000..75754f6e --- /dev/null +++ b/src/main/java/com/peanut/common/service/AsyncService.java @@ -0,0 +1,30 @@ +package com.peanut.common.service; + +import com.aliyun.vod20170321.models.GetVideoPlayAuthResponse; +import com.peanut.common.utils.SpdbUtil; +import com.peanut.modules.common.dao.CourseCatalogueChapterVideoDao; +import com.peanut.modules.common.entity.CourseCatalogueChapterVideoEntity; +import com.peanut.modules.common.entity.UserCourseVideoPositionEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +@Service +public class AsyncService { + @Autowired + private CourseCatalogueChapterVideoDao courseCatalogueChapterVideoDao; + + @Async + public void pushDurationToVideo(Integer videoId) throws Exception { + CourseCatalogueChapterVideoEntity courseCatalogueChapterVideoEntity = courseCatalogueChapterVideoDao.selectById(videoId); + if(courseCatalogueChapterVideoEntity.getType()==1){ + GetVideoPlayAuthResponse p = SpdbUtil.getPlayAuth(courseCatalogueChapterVideoEntity.getVideo()); + int i = p.getBody().getVideoMeta().getDuration().intValue(); + courseCatalogueChapterVideoEntity.setDuration(i); + }else{ + Integer mp4Duration = SpdbUtil.getMp4Duration("https://ehh-private-01.oss-cn-beijing.aliyuncs.com/video/taiHuClass/" + courseCatalogueChapterVideoEntity.getVideo()); + courseCatalogueChapterVideoEntity.setDuration(mp4Duration); + } + courseCatalogueChapterVideoDao.updateById(courseCatalogueChapterVideoEntity); + } +} diff --git a/src/main/java/com/peanut/common/utils/SpdbUtil.java b/src/main/java/com/peanut/common/utils/SpdbUtil.java index 7615fafd..1080f6bd 100644 --- a/src/main/java/com/peanut/common/utils/SpdbUtil.java +++ b/src/main/java/com/peanut/common/utils/SpdbUtil.java @@ -5,11 +5,25 @@ import com.aliyun.teautil.models.RuntimeOptions; import com.aliyun.vod20170321.Client; import com.aliyun.vod20170321.models.GetVideoPlayAuthRequest; import com.aliyun.vod20170321.models.GetVideoPlayAuthResponse; +import org.bytedeco.javacv.FFmpegFrameGrabber; +import org.bytedeco.javacv.FrameGrabber; import java.util.HashMap; public class SpdbUtil { + public static Integer getMp4Duration(String url){ + double duration = 0; + try (FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber(url)) { + frameGrabber.start(); + duration = frameGrabber.getLengthInTime()/1000000; + frameGrabber.stop(); + } catch (FrameGrabber.Exception e) { + e.printStackTrace(); + } + return (int)duration; + }; + public static GetVideoPlayAuthResponse getPlayAuth(String vid) throws Exception { com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config() // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。 diff --git a/src/main/java/com/peanut/config/AsyncConfig.java b/src/main/java/com/peanut/config/AsyncConfig.java new file mode 100644 index 00000000..af100663 --- /dev/null +++ b/src/main/java/com/peanut/config/AsyncConfig.java @@ -0,0 +1,24 @@ +package com.peanut.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; + +@Configuration +@EnableAsync +public class AsyncConfig implements AsyncConfigurer { + @Override + @Bean + public Executor getAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(5); + executor.setMaxPoolSize(10); + executor.setQueueCapacity(25); + executor.initialize(); + return executor; + } +} diff --git a/src/main/java/com/peanut/modules/common/entity/CourseCatalogueChapterVideoEntity.java b/src/main/java/com/peanut/modules/common/entity/CourseCatalogueChapterVideoEntity.java index c4253b43..4a4c1043 100644 --- a/src/main/java/com/peanut/modules/common/entity/CourseCatalogueChapterVideoEntity.java +++ b/src/main/java/com/peanut/modules/common/entity/CourseCatalogueChapterVideoEntity.java @@ -23,6 +23,8 @@ public class CourseCatalogueChapterVideoEntity { private Integer sort; + private Integer duration; + private Date createTime; @TableLogic diff --git a/src/main/java/com/peanut/modules/common/entity/CourseCatalogueEntity.java b/src/main/java/com/peanut/modules/common/entity/CourseCatalogueEntity.java index f27da71f..ffcf94ea 100644 --- a/src/main/java/com/peanut/modules/common/entity/CourseCatalogueEntity.java +++ b/src/main/java/com/peanut/modules/common/entity/CourseCatalogueEntity.java @@ -43,4 +43,9 @@ public class CourseCatalogueEntity{ */ @TableField(exist = false) private Integer isBuy; + /** + * 完成度百分比 + */ + @TableField(exist = false) + private int completion; } diff --git a/src/main/java/com/peanut/modules/common/entity/UserCourseVideoPositionEntity.java b/src/main/java/com/peanut/modules/common/entity/UserCourseVideoPositionEntity.java index e35c3796..d37ebd27 100644 --- a/src/main/java/com/peanut/modules/common/entity/UserCourseVideoPositionEntity.java +++ b/src/main/java/com/peanut/modules/common/entity/UserCourseVideoPositionEntity.java @@ -20,8 +20,6 @@ public class UserCourseVideoPositionEntity { private Integer position; - private Integer duration; - private Date createTime; @TableLogic diff --git a/src/main/java/com/peanut/modules/master/service/impl/CourseCatalogueChapterVideoServiceImpl.java b/src/main/java/com/peanut/modules/master/service/impl/CourseCatalogueChapterVideoServiceImpl.java index d68c29bc..ddd187d6 100644 --- a/src/main/java/com/peanut/modules/master/service/impl/CourseCatalogueChapterVideoServiceImpl.java +++ b/src/main/java/com/peanut/modules/master/service/impl/CourseCatalogueChapterVideoServiceImpl.java @@ -4,6 +4,7 @@ import com.aliyun.vod20170321.models.GetVideoPlayAuthResponse; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.peanut.common.service.AsyncService; import com.peanut.common.utils.ShiroUtils; import com.peanut.common.utils.SpdbUtil; import com.peanut.modules.common.dao.*; @@ -30,11 +31,13 @@ public class CourseCatalogueChapterVideoServiceImpl extends ServiceImpl wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(CourseCatalogueChapterVideoEntity::getChapterId,param.getId()); + wrapper.eq(CourseCatalogueChapterVideoEntity::getChapterId, param.getId()); wrapper.orderByAsc(CourseCatalogueChapterVideoEntity::getSort); Page page = this.page(new Page<>(param.getPage(), param.getLimit()), wrapper); return page; @@ -42,17 +45,21 @@ public class CourseCatalogueChapterVideoServiceImpl extends ServiceImpl userToCourseEntities = userToCourseDao.selectList(new LambdaQueryWrapper().eq(UserToCourseEntity::getUserId, uId).eq(UserToCourseEntity::getCourseId, courseCatalogueEntity.getCourseId())); //用户课程足迹 - if(userToCourseEntities.size()!=0){ + if (userToCourseEntities.size() != 0) { UserToCourseEntity userToCourseEntity = userToCourseEntities.get(0); userToCourseEntity.setUpdateTime(new Date()); userToCourseDao.updateById(userToCourseEntity); - }else{ + } else { UserToCourseEntity userToCourseEntity = new UserToCourseEntity(); userToCourseEntity.setUserId(uId); userToCourseEntity.setCourseId(courseCatalogueEntity.getCourseId()); @@ -61,61 +68,45 @@ public class CourseCatalogueChapterVideoServiceImpl extends ServiceImpl wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(UserCourseVideoPositionEntity::getUserId,uId); - wrapper.eq(UserCourseVideoPositionEntity::getVideoId,videoId); + wrapper.eq(UserCourseVideoPositionEntity::getUserId, uId); + wrapper.eq(UserCourseVideoPositionEntity::getVideoId, videoId); List userCourseVideoPositionEntities = userCourseVideoPositionDao.selectList(wrapper); - if(userCourseVideoPositionEntities.size()==0){ + if (userCourseVideoPositionEntities.size() == 0) { UserCourseVideoPositionEntity userCourseVideoPositionEntity = new UserCourseVideoPositionEntity(); userCourseVideoPositionEntity.setUserId(uId); userCourseVideoPositionEntity.setVideoId(videoId); userCourseVideoPositionDao.insert(userCourseVideoPositionEntity); - }else { + } else { UserCourseVideoPositionEntity userCourseVideoPositionEntity = userCourseVideoPositionEntities.get(0); userCourseVideoPositionEntity.setPosition(position); userCourseVideoPositionDao.updateById(userCourseVideoPositionEntity); } } - private UserCourseVideoPositionEntity getVideoPosition(CourseCatalogueChapterVideoEntity video, int userId, int duration){ + private UserCourseVideoPositionEntity getVideoPosition(CourseCatalogueChapterVideoEntity video, int userId) { List userCourseVideoPositionEntities = userCourseVideoPositionDao.selectList(new LambdaQueryWrapper().eq(UserCourseVideoPositionEntity::getUserId, userId).eq(UserCourseVideoPositionEntity::getVideoId, video.getId())); - if(video.getType()==0){ - if(userCourseVideoPositionEntities.size()>0){ - return userCourseVideoPositionEntities.get(0); - }else{ - UserCourseVideoPositionEntity userCourseVideoPositionEntity = new UserCourseVideoPositionEntity(); - userCourseVideoPositionEntity.setUserId(userId); - userCourseVideoPositionEntity.setVideoId(video.getId()); - userCourseVideoPositionDao.insert(userCourseVideoPositionEntity); - return userCourseVideoPositionEntity; - } - }else{//加密视频 - if(userCourseVideoPositionEntities.size()>0){ - return userCourseVideoPositionEntities.get(0); - }else{ - UserCourseVideoPositionEntity userCourseVideoPositionEntity = new UserCourseVideoPositionEntity(); - userCourseVideoPositionEntity.setUserId(userId); - userCourseVideoPositionEntity.setVideoId(video.getId()); - userCourseVideoPositionEntity.setDuration(duration); - userCourseVideoPositionDao.insert(userCourseVideoPositionEntity); - return userCourseVideoPositionEntity; - } + if (userCourseVideoPositionEntities.size() > 0) { + return userCourseVideoPositionEntities.get(0); + } else { + UserCourseVideoPositionEntity userCourseVideoPositionEntity = new UserCourseVideoPositionEntity(); + userCourseVideoPositionEntity.setUserId(userId); + userCourseVideoPositionEntity.setVideoId(video.getId()); + userCourseVideoPositionEntity.setPosition(0); + userCourseVideoPositionDao.insert(userCourseVideoPositionEntity); + return userCourseVideoPositionEntity; } } } diff --git a/src/main/java/com/peanut/modules/sociology/controller/CourseController.java b/src/main/java/com/peanut/modules/sociology/controller/CourseController.java index 80ac2126..8f812042 100644 --- a/src/main/java/com/peanut/modules/sociology/controller/CourseController.java +++ b/src/main/java/com/peanut/modules/sociology/controller/CourseController.java @@ -17,6 +17,8 @@ import com.peanut.modules.master.service.CourseCatalogueChapterVideoService; import com.peanut.modules.sociology.service.CourseCatalogueChapterService; import com.peanut.modules.sociology.service.CourseService; import lombok.extern.slf4j.Slf4j; +import org.bytedeco.javacv.FFmpegFrameGrabber; +import org.bytedeco.javacv.FrameGrabber; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -112,12 +114,13 @@ public class CourseController { return R.ok().put("playAuth",playAuth); } + @RequestMapping("/saveCoursePosition") public R saveCoursePosition(@RequestBody Map map){ Integer uId = ShiroUtils.getUId(); Integer videoId = map.get("videoId"); Integer position = map.get("position"); courseCatalogueChapterVideoService.saveCoursePosition(uId,videoId,position); - return null; + return R.ok(); } /** * 验证video权限,并解决足迹,加密视频签名问题 diff --git a/src/main/java/com/peanut/modules/sociology/service/impl/CourseCatalogueChapterServiceImpl.java b/src/main/java/com/peanut/modules/sociology/service/impl/CourseCatalogueChapterServiceImpl.java index 103827fa..ff94edf9 100644 --- a/src/main/java/com/peanut/modules/sociology/service/impl/CourseCatalogueChapterServiceImpl.java +++ b/src/main/java/com/peanut/modules/sociology/service/impl/CourseCatalogueChapterServiceImpl.java @@ -38,4 +38,6 @@ public class CourseCatalogueChapterServiceImpl extends ServiceImpl impl private CourseCatalogueDao courseCatalogueDao; @Autowired private UserCourseBuyDao userCourseBuyDao; + @Autowired + private CourseCatalogueChapterDao courseCatalogueChapterDao; + @Autowired + private CourseCatalogueChapterVideoDao courseCatalogueChapterVideoDao; + @Autowired + private UserCourseVideoPositionDao userCourseVideoPositionDao; //根据标签获取课程列表 @@ -77,15 +84,37 @@ public class CourseServiceImpl extends ServiceImpl impl @Override public Map getCourseDetail(Integer id) { Map flag = new HashMap<>(); + //基础信息 CourseEntity course = this.getById(id); flag.put("course",course); + //目录信息 List courseCatalogueEntities = courseCatalogueDao.selectList(new LambdaQueryWrapper().eq(CourseCatalogueEntity::getCourseId, id)); Integer uId = ShiroUtils.getUId(); for (CourseCatalogueEntity c :courseCatalogueEntities){ Integer integer = userCourseBuyDao.selectCount(new LambdaQueryWrapper().eq(UserCourseBuyEntity::getUserId, uId).eq(UserCourseBuyEntity::getCatalogueId, c.getId())); c.setIsBuy(integer>0?1:0); + c.setCompletion(catalogueCompletion(c)); } flag.put("catalogues",courseCatalogueEntities); return flag; } + + private Integer catalogueCompletion(CourseCatalogueEntity c){ + List courseCatalogueChapterEntities = courseCatalogueChapterDao.selectList(new LambdaQueryWrapper().eq(CourseCatalogueChapterEntity::getCatalogueId, c.getId())); + Integer act = 0; + for (CourseCatalogueChapterEntity cc : courseCatalogueChapterEntities){ + List courseCatalogueChapterVideoEntities = courseCatalogueChapterVideoDao.selectList(new LambdaQueryWrapper().eq(CourseCatalogueChapterVideoEntity::getChapterId, cc.getId())); + List collect = courseCatalogueChapterVideoEntities.stream().map(CourseCatalogueChapterVideoEntity::getId).collect(Collectors.toList()); + if(collect.size()==0){ + continue; + } + Integer integer = userCourseVideoPositionDao.selectCount(new LambdaQueryWrapper().eq(UserCourseVideoPositionEntity::getUserId, ShiroUtils.getUId()).in(UserCourseVideoPositionEntity::getVideoId, collect)); + if (integer>0){ + act++; + } + } + return courseCatalogueChapterEntities.size()==0?0:act * 100 / courseCatalogueChapterEntities.size(); + } + + }