时长信息转到video主体 增加多线程获取时间方法

This commit is contained in:
wangjinlei
2024-04-26 10:44:48 +08:00
parent 6b2e37b29b
commit 5c7d424f5e
11 changed files with 154 additions and 42 deletions

18
pom.xml
View File

@@ -135,7 +135,11 @@
<version>3.12.5</version> <version>3.12.5</version>
</dependency> </dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.6</version>
</dependency>
<!--阿里短信服务--> <!--阿里短信服务-->
<dependency> <dependency>
<groupId>com.aliyun</groupId> <groupId>com.aliyun</groupId>
@@ -187,7 +191,7 @@
<artifactId>aspose-words</artifactId> <artifactId>aspose-words</artifactId>
<version>aspose-words-22.10-jdk16</version> <version>aspose-words-22.10-jdk16</version>
<scope>system</scope> <scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/lib/aspose-words-22.10-jdk16.jar</systemPath> <systemPath>${pom.basedir}/src/main/resources/lib/aspose-words-22.10-jdk16.jar</systemPath>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jsoup</groupId> <groupId>org.jsoup</groupId>
@@ -483,6 +487,16 @@
<enabled>true</enabled> <enabled>true</enabled>
</releases> </releases>
</repository> </repository>
<repository>
<id>central</id>
<url>https://maven.aliyun.com/repository/central</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository> <repository>
<id>com.e-iceblue</id> <id>com.e-iceblue</id>
<url>https://repo.e-iceblue.cn/repository/maven-public/</url> <url>https://repo.e-iceblue.cn/repository/maven-public/</url>

View File

@@ -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);
}
}

View File

@@ -5,11 +5,25 @@ import com.aliyun.teautil.models.RuntimeOptions;
import com.aliyun.vod20170321.Client; import com.aliyun.vod20170321.Client;
import com.aliyun.vod20170321.models.GetVideoPlayAuthRequest; import com.aliyun.vod20170321.models.GetVideoPlayAuthRequest;
import com.aliyun.vod20170321.models.GetVideoPlayAuthResponse; import com.aliyun.vod20170321.models.GetVideoPlayAuthResponse;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FrameGrabber;
import java.util.HashMap; import java.util.HashMap;
public class SpdbUtil { 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 { public static GetVideoPlayAuthResponse getPlayAuth(String vid) throws Exception {
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config() com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。 // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。

View File

@@ -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;
}
}

View File

@@ -23,6 +23,8 @@ public class CourseCatalogueChapterVideoEntity {
private Integer sort; private Integer sort;
private Integer duration;
private Date createTime; private Date createTime;
@TableLogic @TableLogic

View File

@@ -43,4 +43,9 @@ public class CourseCatalogueEntity{
*/ */
@TableField(exist = false) @TableField(exist = false)
private Integer isBuy; private Integer isBuy;
/**
* 完成度百分比
*/
@TableField(exist = false)
private int completion;
} }

View File

@@ -20,8 +20,6 @@ public class UserCourseVideoPositionEntity {
private Integer position; private Integer position;
private Integer duration;
private Date createTime; private Date createTime;
@TableLogic @TableLogic

View File

@@ -4,6 +4,7 @@ import com.aliyun.vod20170321.models.GetVideoPlayAuthResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 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.ShiroUtils;
import com.peanut.common.utils.SpdbUtil; import com.peanut.common.utils.SpdbUtil;
import com.peanut.modules.common.dao.*; import com.peanut.modules.common.dao.*;
@@ -30,11 +31,13 @@ public class CourseCatalogueChapterVideoServiceImpl extends ServiceImpl<CourseCa
private UserToCourseDao userToCourseDao; private UserToCourseDao userToCourseDao;
@Autowired @Autowired
private UserCourseVideoPositionDao userCourseVideoPositionDao; private UserCourseVideoPositionDao userCourseVideoPositionDao;
@Autowired
private AsyncService asyncService;
@Override @Override
public Page getCourseCatalogueChapterVideoList(ParamTo param) { public Page getCourseCatalogueChapterVideoList(ParamTo param) {
LambdaQueryWrapper<CourseCatalogueChapterVideoEntity> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<CourseCatalogueChapterVideoEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CourseCatalogueChapterVideoEntity::getChapterId,param.getId()); wrapper.eq(CourseCatalogueChapterVideoEntity::getChapterId, param.getId());
wrapper.orderByAsc(CourseCatalogueChapterVideoEntity::getSort); wrapper.orderByAsc(CourseCatalogueChapterVideoEntity::getSort);
Page<CourseCatalogueChapterVideoEntity> page = this.page(new Page<>(param.getPage(), param.getLimit()), wrapper); Page<CourseCatalogueChapterVideoEntity> page = this.page(new Page<>(param.getPage(), param.getLimit()), wrapper);
return page; return page;
@@ -42,17 +45,21 @@ public class CourseCatalogueChapterVideoServiceImpl extends ServiceImpl<CourseCa
@Override @Override
public CourseCatalogueChapterVideoEntity checkVideo(CourseCatalogueChapterVideoEntity video) throws Exception { public CourseCatalogueChapterVideoEntity checkVideo(CourseCatalogueChapterVideoEntity videoEntity) throws Exception {
CourseCatalogueChapterVideoEntity video = this.getById(videoEntity.getId());
if (video.getDuration() == 0) {
asyncService.pushDurationToVideo(video.getId());
}
CourseCatalogueChapterEntity courseCatalogueChapterEntity = courseCatalogueChapterDao.selectById(video.getChapterId()); CourseCatalogueChapterEntity courseCatalogueChapterEntity = courseCatalogueChapterDao.selectById(video.getChapterId());
CourseCatalogueEntity courseCatalogueEntity = courseCatalogueDao.selectById(courseCatalogueChapterEntity.getCatalogueId()); CourseCatalogueEntity courseCatalogueEntity = courseCatalogueDao.selectById(courseCatalogueChapterEntity.getCatalogueId());
Integer uId = ShiroUtils.getUId(); Integer uId = ShiroUtils.getUId();
List<UserToCourseEntity> userToCourseEntities = userToCourseDao.selectList(new LambdaQueryWrapper<UserToCourseEntity>().eq(UserToCourseEntity::getUserId, uId).eq(UserToCourseEntity::getCourseId, courseCatalogueEntity.getCourseId())); List<UserToCourseEntity> userToCourseEntities = userToCourseDao.selectList(new LambdaQueryWrapper<UserToCourseEntity>().eq(UserToCourseEntity::getUserId, uId).eq(UserToCourseEntity::getCourseId, courseCatalogueEntity.getCourseId()));
//用户课程足迹 //用户课程足迹
if(userToCourseEntities.size()!=0){ if (userToCourseEntities.size() != 0) {
UserToCourseEntity userToCourseEntity = userToCourseEntities.get(0); UserToCourseEntity userToCourseEntity = userToCourseEntities.get(0);
userToCourseEntity.setUpdateTime(new Date()); userToCourseEntity.setUpdateTime(new Date());
userToCourseDao.updateById(userToCourseEntity); userToCourseDao.updateById(userToCourseEntity);
}else{ } else {
UserToCourseEntity userToCourseEntity = new UserToCourseEntity(); UserToCourseEntity userToCourseEntity = new UserToCourseEntity();
userToCourseEntity.setUserId(uId); userToCourseEntity.setUserId(uId);
userToCourseEntity.setCourseId(courseCatalogueEntity.getCourseId()); userToCourseEntity.setCourseId(courseCatalogueEntity.getCourseId());
@@ -61,61 +68,45 @@ public class CourseCatalogueChapterVideoServiceImpl extends ServiceImpl<CourseCa
userToCourseDao.insert(userToCourseEntity); userToCourseDao.insert(userToCourseEntity);
} }
//加密视频组装playauth //加密视频组装playauth
if(video.getType()==1){ if (video.getType() == 1) {
GetVideoPlayAuthResponse p = SpdbUtil.getPlayAuth(video.getVideo()); GetVideoPlayAuthResponse p = SpdbUtil.getPlayAuth(video.getVideo());
String playAuth = p.getBody().getPlayAuth(); String playAuth = p.getBody().getPlayAuth();
video.setPlayAuth(playAuth); video.setPlayAuth(playAuth);
//获取播放记录
UserCourseVideoPositionEntity videoPosition = getVideoPosition(video, uId, p.getBody().getVideoMeta().getDuration().intValue());
video.setUserCourseVideoPositionEntity(videoPosition);
}else{
UserCourseVideoPositionEntity videoPosition = getVideoPosition(video, uId, 0);
video.setUserCourseVideoPositionEntity(videoPosition);
} }
UserCourseVideoPositionEntity videoPosition = getVideoPosition(video, uId);
video.setUserCourseVideoPositionEntity(videoPosition);
return video; return video;
} }
@Override @Override
public void saveCoursePosition(int uId, int videoId, int position) { public void saveCoursePosition(int uId, int videoId, int position) {
LambdaQueryWrapper<UserCourseVideoPositionEntity> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<UserCourseVideoPositionEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(UserCourseVideoPositionEntity::getUserId,uId); wrapper.eq(UserCourseVideoPositionEntity::getUserId, uId);
wrapper.eq(UserCourseVideoPositionEntity::getVideoId,videoId); wrapper.eq(UserCourseVideoPositionEntity::getVideoId, videoId);
List<UserCourseVideoPositionEntity> userCourseVideoPositionEntities = userCourseVideoPositionDao.selectList(wrapper); List<UserCourseVideoPositionEntity> userCourseVideoPositionEntities = userCourseVideoPositionDao.selectList(wrapper);
if(userCourseVideoPositionEntities.size()==0){ if (userCourseVideoPositionEntities.size() == 0) {
UserCourseVideoPositionEntity userCourseVideoPositionEntity = new UserCourseVideoPositionEntity(); UserCourseVideoPositionEntity userCourseVideoPositionEntity = new UserCourseVideoPositionEntity();
userCourseVideoPositionEntity.setUserId(uId); userCourseVideoPositionEntity.setUserId(uId);
userCourseVideoPositionEntity.setVideoId(videoId); userCourseVideoPositionEntity.setVideoId(videoId);
userCourseVideoPositionDao.insert(userCourseVideoPositionEntity); userCourseVideoPositionDao.insert(userCourseVideoPositionEntity);
}else { } else {
UserCourseVideoPositionEntity userCourseVideoPositionEntity = userCourseVideoPositionEntities.get(0); UserCourseVideoPositionEntity userCourseVideoPositionEntity = userCourseVideoPositionEntities.get(0);
userCourseVideoPositionEntity.setPosition(position); userCourseVideoPositionEntity.setPosition(position);
userCourseVideoPositionDao.updateById(userCourseVideoPositionEntity); userCourseVideoPositionDao.updateById(userCourseVideoPositionEntity);
} }
} }
private UserCourseVideoPositionEntity getVideoPosition(CourseCatalogueChapterVideoEntity video, int userId, int duration){ private UserCourseVideoPositionEntity getVideoPosition(CourseCatalogueChapterVideoEntity video, int userId) {
List<UserCourseVideoPositionEntity> userCourseVideoPositionEntities = userCourseVideoPositionDao.selectList(new LambdaQueryWrapper<UserCourseVideoPositionEntity>().eq(UserCourseVideoPositionEntity::getUserId, userId).eq(UserCourseVideoPositionEntity::getVideoId, video.getId())); List<UserCourseVideoPositionEntity> userCourseVideoPositionEntities = userCourseVideoPositionDao.selectList(new LambdaQueryWrapper<UserCourseVideoPositionEntity>().eq(UserCourseVideoPositionEntity::getUserId, userId).eq(UserCourseVideoPositionEntity::getVideoId, video.getId()));
if(video.getType()==0){ if (userCourseVideoPositionEntities.size() > 0) {
if(userCourseVideoPositionEntities.size()>0){ return userCourseVideoPositionEntities.get(0);
return userCourseVideoPositionEntities.get(0); } else {
}else{ UserCourseVideoPositionEntity userCourseVideoPositionEntity = new UserCourseVideoPositionEntity();
UserCourseVideoPositionEntity userCourseVideoPositionEntity = new UserCourseVideoPositionEntity(); userCourseVideoPositionEntity.setUserId(userId);
userCourseVideoPositionEntity.setUserId(userId); userCourseVideoPositionEntity.setVideoId(video.getId());
userCourseVideoPositionEntity.setVideoId(video.getId()); userCourseVideoPositionEntity.setPosition(0);
userCourseVideoPositionDao.insert(userCourseVideoPositionEntity); userCourseVideoPositionDao.insert(userCourseVideoPositionEntity);
return 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;
}
} }
} }
} }

View File

@@ -17,6 +17,8 @@ import com.peanut.modules.master.service.CourseCatalogueChapterVideoService;
import com.peanut.modules.sociology.service.CourseCatalogueChapterService; import com.peanut.modules.sociology.service.CourseCatalogueChapterService;
import com.peanut.modules.sociology.service.CourseService; import com.peanut.modules.sociology.service.CourseService;
import lombok.extern.slf4j.Slf4j; 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.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@@ -112,12 +114,13 @@ public class CourseController {
return R.ok().put("playAuth",playAuth); return R.ok().put("playAuth",playAuth);
} }
@RequestMapping("/saveCoursePosition")
public R saveCoursePosition(@RequestBody Map<String,Integer> map){ public R saveCoursePosition(@RequestBody Map<String,Integer> map){
Integer uId = ShiroUtils.getUId(); Integer uId = ShiroUtils.getUId();
Integer videoId = map.get("videoId"); Integer videoId = map.get("videoId");
Integer position = map.get("position"); Integer position = map.get("position");
courseCatalogueChapterVideoService.saveCoursePosition(uId,videoId,position); courseCatalogueChapterVideoService.saveCoursePosition(uId,videoId,position);
return null; return R.ok();
} }
/** /**
* 验证video权限并解决足迹加密视频签名问题 * 验证video权限并解决足迹加密视频签名问题

View File

@@ -38,4 +38,6 @@ public class CourseCatalogueChapterServiceImpl extends ServiceImpl<CourseCatalog
flag.put("videos",courseCatalogueChapterVideoEntities); flag.put("videos",courseCatalogueChapterVideoEntities);
return flag; return flag;
} }
} }

View File

@@ -17,6 +17,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors;
@Slf4j @Slf4j
@Service("sociologyCourseService") @Service("sociologyCourseService")
@@ -30,6 +31,12 @@ public class CourseServiceImpl extends ServiceImpl<CourseDao, CourseEntity> impl
private CourseCatalogueDao courseCatalogueDao; private CourseCatalogueDao courseCatalogueDao;
@Autowired @Autowired
private UserCourseBuyDao userCourseBuyDao; private UserCourseBuyDao userCourseBuyDao;
@Autowired
private CourseCatalogueChapterDao courseCatalogueChapterDao;
@Autowired
private CourseCatalogueChapterVideoDao courseCatalogueChapterVideoDao;
@Autowired
private UserCourseVideoPositionDao userCourseVideoPositionDao;
//根据标签获取课程列表 //根据标签获取课程列表
@@ -77,15 +84,37 @@ public class CourseServiceImpl extends ServiceImpl<CourseDao, CourseEntity> impl
@Override @Override
public Map<String, Object> getCourseDetail(Integer id) { public Map<String, Object> getCourseDetail(Integer id) {
Map<String, Object> flag = new HashMap<>(); Map<String, Object> flag = new HashMap<>();
//基础信息
CourseEntity course = this.getById(id); CourseEntity course = this.getById(id);
flag.put("course",course); flag.put("course",course);
//目录信息
List<CourseCatalogueEntity> courseCatalogueEntities = courseCatalogueDao.selectList(new LambdaQueryWrapper<CourseCatalogueEntity>().eq(CourseCatalogueEntity::getCourseId, id)); List<CourseCatalogueEntity> courseCatalogueEntities = courseCatalogueDao.selectList(new LambdaQueryWrapper<CourseCatalogueEntity>().eq(CourseCatalogueEntity::getCourseId, id));
Integer uId = ShiroUtils.getUId(); Integer uId = ShiroUtils.getUId();
for (CourseCatalogueEntity c :courseCatalogueEntities){ for (CourseCatalogueEntity c :courseCatalogueEntities){
Integer integer = userCourseBuyDao.selectCount(new LambdaQueryWrapper<UserCourseBuyEntity>().eq(UserCourseBuyEntity::getUserId, uId).eq(UserCourseBuyEntity::getCatalogueId, c.getId())); Integer integer = userCourseBuyDao.selectCount(new LambdaQueryWrapper<UserCourseBuyEntity>().eq(UserCourseBuyEntity::getUserId, uId).eq(UserCourseBuyEntity::getCatalogueId, c.getId()));
c.setIsBuy(integer>0?1:0); c.setIsBuy(integer>0?1:0);
c.setCompletion(catalogueCompletion(c));
} }
flag.put("catalogues",courseCatalogueEntities); flag.put("catalogues",courseCatalogueEntities);
return flag; return flag;
} }
private Integer catalogueCompletion(CourseCatalogueEntity c){
List<CourseCatalogueChapterEntity> courseCatalogueChapterEntities = courseCatalogueChapterDao.selectList(new LambdaQueryWrapper<CourseCatalogueChapterEntity>().eq(CourseCatalogueChapterEntity::getCatalogueId, c.getId()));
Integer act = 0;
for (CourseCatalogueChapterEntity cc : courseCatalogueChapterEntities){
List<CourseCatalogueChapterVideoEntity> courseCatalogueChapterVideoEntities = courseCatalogueChapterVideoDao.selectList(new LambdaQueryWrapper<CourseCatalogueChapterVideoEntity>().eq(CourseCatalogueChapterVideoEntity::getChapterId, cc.getId()));
List<Integer> collect = courseCatalogueChapterVideoEntities.stream().map(CourseCatalogueChapterVideoEntity::getId).collect(Collectors.toList());
if(collect.size()==0){
continue;
}
Integer integer = userCourseVideoPositionDao.selectCount(new LambdaQueryWrapper<UserCourseVideoPositionEntity>().eq(UserCourseVideoPositionEntity::getUserId, ShiroUtils.getUId()).in(UserCourseVideoPositionEntity::getVideoId, collect));
if (integer>0){
act++;
}
}
return courseCatalogueChapterEntities.size()==0?0:act * 100 / courseCatalogueChapterEntities.size();
}
} }