新增视频转码,进度显示功能
This commit is contained in:
parent
15b0ec994a
commit
4c6c5d00c9
@ -17,22 +17,40 @@ import org.springframework.stereotype.Component;
|
|||||||
@ConfigurationProperties(prefix = "media.video")
|
@ConfigurationProperties(prefix = "media.video")
|
||||||
public class VideoProperties {
|
public class VideoProperties {
|
||||||
|
|
||||||
private Long backendDuration;
|
private String types;
|
||||||
private Long appDuration;
|
private Integer maxUploadCount;
|
||||||
|
private Long backendMaxDuration;
|
||||||
|
private Long appMaxDuration;
|
||||||
|
|
||||||
public Long getBackendDuration() {
|
public String getTypes() {
|
||||||
return backendDuration;
|
return types == null ? "mp4" : types;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBackendDuration(Long backendDuration) {
|
public void setTypes(String types) {
|
||||||
this.backendDuration = backendDuration;
|
this.types = types;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getAppDuration() {
|
public Integer getMaxUploadCount() {
|
||||||
return appDuration;
|
return maxUploadCount == null || maxUploadCount <= 1 ? 1 : maxUploadCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAppDuration(Long appDuration) {
|
public void setMaxUploadCount(Integer maxUploadCount) {
|
||||||
this.appDuration = appDuration;
|
this.maxUploadCount = maxUploadCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getBackendMaxDuration() {
|
||||||
|
return backendMaxDuration == null || backendMaxDuration <= 0 ? 0 : backendMaxDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBackendMaxDuration(Long backendMaxDuration) {
|
||||||
|
this.backendMaxDuration = backendMaxDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAppMaxDuration() {
|
||||||
|
return appMaxDuration == null || appMaxDuration <= 0 ? 0 : appMaxDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAppMaxDuration(Long appMaxDuration) {
|
||||||
|
this.appMaxDuration = appMaxDuration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,24 @@ package ink.wgink.module.file.media.controller.api.video;
|
|||||||
import ink.wgink.common.base.DefaultBaseController;
|
import ink.wgink.common.base.DefaultBaseController;
|
||||||
import ink.wgink.exceptions.PropertiesException;
|
import ink.wgink.exceptions.PropertiesException;
|
||||||
import ink.wgink.interfaces.consts.ISystemConstant;
|
import ink.wgink.interfaces.consts.ISystemConstant;
|
||||||
|
import ink.wgink.module.file.media.pojo.dtos.video.VideoDTO;
|
||||||
import ink.wgink.module.file.media.service.video.IVideoService;
|
import ink.wgink.module.file.media.service.video.IVideoService;
|
||||||
|
import ink.wgink.pojo.ListPage;
|
||||||
import ink.wgink.pojo.result.ErrorResult;
|
import ink.wgink.pojo.result.ErrorResult;
|
||||||
|
import ink.wgink.pojo.result.SuccessResult;
|
||||||
import ink.wgink.pojo.result.SuccessResultData;
|
import ink.wgink.pojo.result.SuccessResultData;
|
||||||
|
import ink.wgink.pojo.result.SuccessResultList;
|
||||||
import ink.wgink.properties.media.MediaProperties;
|
import ink.wgink.properties.media.MediaProperties;
|
||||||
import io.swagger.annotations.*;
|
import io.swagger.annotations.*;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,7 +35,7 @@ import java.util.concurrent.Callable;
|
|||||||
**/
|
**/
|
||||||
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "视频接口")
|
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "视频接口")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(ISystemConstant.API_PREFIX + "/video")
|
@RequestMapping(ISystemConstant.API_PREFIX + "/file/media/video")
|
||||||
public class VideoController extends DefaultBaseController {
|
public class VideoController extends DefaultBaseController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@ -39,9 +44,6 @@ public class VideoController extends DefaultBaseController {
|
|||||||
private IVideoService videoService;
|
private IVideoService videoService;
|
||||||
|
|
||||||
@ApiOperation(value = "上传视频", notes = "上传视频接口")
|
@ApiOperation(value = "上传视频", notes = "上传视频接口")
|
||||||
@ApiImplicitParams({
|
|
||||||
@ApiImplicitParam(name = "video", value = "文件video", paramType = "query")
|
|
||||||
})
|
|
||||||
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
|
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
|
||||||
@PostMapping("upload")
|
@PostMapping("upload")
|
||||||
public Callable<SuccessResultData<String>> upload(@RequestParam("video") MultipartFile video) {
|
public Callable<SuccessResultData<String>> upload(@RequestParam("video") MultipartFile video) {
|
||||||
@ -54,4 +56,53 @@ public class VideoController extends DefaultBaseController {
|
|||||||
return () -> new SuccessResultData<>(videoService.upload(video));
|
return () -> new SuccessResultData<>(videoService.upload(video));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "删除文件类别(id列表)", notes = "删除文件类别(id列表)接口")
|
||||||
|
@ApiImplicitParams({
|
||||||
|
@ApiImplicitParam(name = "ids", value = "ID列表,用下划线分隔", paramType = "path", example = "1_2_3")
|
||||||
|
})
|
||||||
|
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
|
||||||
|
@DeleteMapping("remove/{isRemoveSource}/{ids}")
|
||||||
|
public synchronized SuccessResult remove(@PathVariable() Integer isRemoveSource, @PathVariable("ids") String ids) {
|
||||||
|
if (isRemoveSource == 0) {
|
||||||
|
videoService.remove(Arrays.asList(ids.split("\\_")));
|
||||||
|
}
|
||||||
|
if (isRemoveSource == 1) {
|
||||||
|
videoService.delete(Arrays.asList(ids.split("\\_")));
|
||||||
|
}
|
||||||
|
return new SuccessResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "视频转码", notes = "视频转码接口")
|
||||||
|
@ApiImplicitParams({
|
||||||
|
@ApiImplicitParam(name = "ids", value = "ID列表,用下划线分隔", paramType = "path", example = "1_2_3")
|
||||||
|
})
|
||||||
|
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
|
||||||
|
@PutMapping("convert/{fileId}")
|
||||||
|
public synchronized SuccessResult updateConvert(@PathVariable("fileId") String fileId) {
|
||||||
|
videoService.updateConvert(fileId);
|
||||||
|
return new SuccessResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "视频转换进度", notes = "视频转换进度接口")
|
||||||
|
@GetMapping(value = "get-convert-progress", produces = "text/event-stream")
|
||||||
|
public SseEmitter getConvertProgress() {
|
||||||
|
return videoService.getConvertProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "视频分页列表", notes = "视频分页列表接口")
|
||||||
|
@ApiImplicitParams({
|
||||||
|
@ApiImplicitParam(name = "page", value = "当前页码", paramType = "query", dataType = "int", defaultValue = "1"),
|
||||||
|
@ApiImplicitParam(name = "rows", value = "显示数量", paramType = "query", dataType = "int", defaultValue = "20"),
|
||||||
|
@ApiImplicitParam(name = "keywords", value = "关键字", paramType = "query", dataType = "String"),
|
||||||
|
@ApiImplicitParam(name = "startTime", value = "开始时间", paramType = "query", dataType = "String"),
|
||||||
|
@ApiImplicitParam(name = "endTime", value = "结束时间", paramType = "query", dataType = "String")
|
||||||
|
})
|
||||||
|
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
|
||||||
|
@GetMapping("listpage")
|
||||||
|
public SuccessResultList<List<VideoDTO>> listPageInfo(ListPage page) {
|
||||||
|
Map<String, Object> params = requestParams();
|
||||||
|
page.setParams(params);
|
||||||
|
return videoService.listPage(page);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
package ink.wgink.module.file.media.controller.route.video;
|
||||||
|
|
||||||
|
import ink.wgink.interfaces.consts.ISystemConstant;
|
||||||
|
import ink.wgink.properties.media.video.VideoProperties;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When you feel like quitting. Think about why you started
|
||||||
|
* 当你想要放弃的时候,想想当初你为何开始
|
||||||
|
*
|
||||||
|
* @ClassName: VideoRouteController
|
||||||
|
* @Description: 视频路由
|
||||||
|
* @Author: wanggeng
|
||||||
|
* @Date: 2021/6/12 11:16 下午
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "文件管理接口")
|
||||||
|
@Controller
|
||||||
|
@RequestMapping(ISystemConstant.ROUTE_PREFIX + "/file/media/video")
|
||||||
|
public class VideoRouteController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private VideoProperties videoProperties;
|
||||||
|
|
||||||
|
@GetMapping("list")
|
||||||
|
public ModelAndView list() {
|
||||||
|
return new ModelAndView("file/media/video/list");
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("upload")
|
||||||
|
public ModelAndView upload() {
|
||||||
|
ModelAndView modelAndView = new ModelAndView("file/media/video/upload");
|
||||||
|
modelAndView.addObject("types", videoProperties.getTypes());
|
||||||
|
modelAndView.addObject("maxUploadCount", videoProperties.getMaxUploadCount());
|
||||||
|
return modelAndView;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
package ink.wgink.module.file.media.dao.video;
|
||||||
|
|
||||||
|
import ink.wgink.exceptions.RemoveException;
|
||||||
|
import ink.wgink.exceptions.SaveException;
|
||||||
|
import ink.wgink.exceptions.SearchException;
|
||||||
|
import ink.wgink.exceptions.UpdateException;
|
||||||
|
import ink.wgink.module.file.media.pojo.dtos.video.VideoDTO;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When you feel like quitting. Think about why you started
|
||||||
|
* 当你想要放弃的时候,想想当初你为何开始
|
||||||
|
*
|
||||||
|
* @ClassName: IVideoDao
|
||||||
|
* @Description: 视频
|
||||||
|
* @Author: wanggeng
|
||||||
|
* @Date: 2021/6/12 10:25 下午
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public interface IVideoDao {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 建表
|
||||||
|
*
|
||||||
|
* @throws UpdateException
|
||||||
|
*/
|
||||||
|
void createTable() throws UpdateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增
|
||||||
|
*
|
||||||
|
* @param params
|
||||||
|
* @throws SaveException
|
||||||
|
*/
|
||||||
|
void save(Map<String, Object> params) throws SaveException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
*
|
||||||
|
* @param params
|
||||||
|
* @throws RemoveException
|
||||||
|
*/
|
||||||
|
void remove(Map<String, Object> params) throws RemoveException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除(物理)
|
||||||
|
*
|
||||||
|
* @param params
|
||||||
|
* @throws RemoveException
|
||||||
|
*/
|
||||||
|
void delete(Map<String, Object> params) throws RemoveException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新
|
||||||
|
*
|
||||||
|
* @param params
|
||||||
|
* @throws UpdateException
|
||||||
|
*/
|
||||||
|
void update(Map<String, Object> params) throws UpdateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新(转码状态)
|
||||||
|
*
|
||||||
|
* @param params
|
||||||
|
* @throws UpdateException
|
||||||
|
*/
|
||||||
|
void updateConvert(Map<String, Object> params) throws UpdateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 详情
|
||||||
|
*
|
||||||
|
* @param params
|
||||||
|
* @return
|
||||||
|
* @throws SearchException
|
||||||
|
*/
|
||||||
|
VideoDTO get(Map<String, Object> params) throws SearchException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表
|
||||||
|
*
|
||||||
|
* @param params
|
||||||
|
* @return
|
||||||
|
* @throws SearchException
|
||||||
|
*/
|
||||||
|
List<VideoDTO> list(Map<String, Object> params) throws SearchException;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package ink.wgink.module.file.media.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When you feel like quitting. Think about why you started
|
||||||
|
* 当你想要放弃的时候,想想当初你为何开始
|
||||||
|
*
|
||||||
|
* @ClassName: ConvertStatusEnum
|
||||||
|
* @Description: 转码状态
|
||||||
|
* @Author: wanggeng
|
||||||
|
* @Date: 2021/6/13 5:06 下午
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public enum ConvertStatusEnum {
|
||||||
|
|
||||||
|
UN_CONVERTED("UN_CONVERTED", "未转码"),
|
||||||
|
CONVERTING("CONVERTING", "转码中"),
|
||||||
|
CONVERTED("CONVERTED", "已转码");
|
||||||
|
|
||||||
|
String value;
|
||||||
|
String summary;
|
||||||
|
|
||||||
|
ConvertStatusEnum(String value, String summary) {
|
||||||
|
this.value = value;
|
||||||
|
this.summary = summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value == null ? "" : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSummary() {
|
||||||
|
return summary == null ? "" : summary;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package ink.wgink.module.file.media.pojo.dtos;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When you feel like quitting. Think about why you started
|
||||||
|
* 当你想要放弃的时候,想想当初你为何开始
|
||||||
|
*
|
||||||
|
* @ClassName: ConvertProcessDTO
|
||||||
|
* @Description: 转换进度
|
||||||
|
* @Author: wanggeng
|
||||||
|
* @Date: 2021/6/13 10:32 下午
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class ConvertProgressDTO {
|
||||||
|
|
||||||
|
private String fileId;
|
||||||
|
private Double percent;
|
||||||
|
|
||||||
|
public String getFileId() {
|
||||||
|
return fileId == null ? "" : fileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileId(String fileId) {
|
||||||
|
this.fileId = fileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getPercent() {
|
||||||
|
return percent == null ? 0 : percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPercent(Double percent) {
|
||||||
|
this.percent = percent;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,117 @@
|
|||||||
|
package ink.wgink.module.file.media.pojo.dtos;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When you feel like quitting. Think about why you started
|
||||||
|
* 当你想要放弃的时候,想想当初你为何开始
|
||||||
|
*
|
||||||
|
* @ClassName: MediaDTO
|
||||||
|
* @Description: 媒体
|
||||||
|
* @Author: wanggeng
|
||||||
|
* @Date: 2021/6/13 4:51 下午
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class MediaDTO implements Serializable {
|
||||||
|
private static final long serialVersionUID = 4546445666757053123L;
|
||||||
|
|
||||||
|
private String fileId;
|
||||||
|
private String fileName;
|
||||||
|
private String filePath;
|
||||||
|
private String fileFullPath;
|
||||||
|
private String fileUrl;
|
||||||
|
private String fileType;
|
||||||
|
private Long fileSize;
|
||||||
|
private String fileSummary;
|
||||||
|
private String fileMd5;
|
||||||
|
private Integer isBack;
|
||||||
|
private String staticUrl;
|
||||||
|
|
||||||
|
public String getFileId() {
|
||||||
|
return fileId == null ? "" : fileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileId(String fileId) {
|
||||||
|
this.fileId = fileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileName() {
|
||||||
|
return fileName == null ? "" : fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileName(String fileName) {
|
||||||
|
this.fileName = fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFilePath() {
|
||||||
|
return filePath == null ? "" : filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilePath(String filePath) {
|
||||||
|
this.filePath = filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileFullPath() {
|
||||||
|
return fileFullPath == null ? "" : fileFullPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileFullPath(String fileFullPath) {
|
||||||
|
this.fileFullPath = fileFullPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileUrl() {
|
||||||
|
return fileUrl == null ? "" : fileUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileUrl(String fileUrl) {
|
||||||
|
this.fileUrl = fileUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileType() {
|
||||||
|
return fileType == null ? "" : fileType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileType(String fileType) {
|
||||||
|
this.fileType = fileType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getFileSize() {
|
||||||
|
return fileSize == null ? 0 : fileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileSize(Long fileSize) {
|
||||||
|
this.fileSize = fileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileSummary() {
|
||||||
|
return fileSummary == null ? "" : fileSummary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileSummary(String fileSummary) {
|
||||||
|
this.fileSummary = fileSummary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileMd5() {
|
||||||
|
return fileMd5 == null ? "" : fileMd5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileMd5(String fileMd5) {
|
||||||
|
this.fileMd5 = fileMd5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getIsBack() {
|
||||||
|
return isBack == null ? 0 : isBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsBack(Integer isBack) {
|
||||||
|
this.isBack = isBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStaticUrl() {
|
||||||
|
return staticUrl == null ? "" : staticUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStaticUrl(String staticUrl) {
|
||||||
|
this.staticUrl = staticUrl;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
package ink.wgink.module.file.media.pojo.dtos.video;
|
||||||
|
|
||||||
|
import ink.wgink.module.file.media.pojo.dtos.MediaDTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When you feel like quitting. Think about why you started
|
||||||
|
* 当你想要放弃的时候,想想当初你为何开始
|
||||||
|
*
|
||||||
|
* @ClassName: VideoDTO
|
||||||
|
* @Description: 视频
|
||||||
|
* @Author: wanggeng
|
||||||
|
* @Date: 2021/6/13 4:53 下午
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class VideoDTO extends MediaDTO {
|
||||||
|
private static final long serialVersionUID = -7694278158868881064L;
|
||||||
|
|
||||||
|
private String keyframe;
|
||||||
|
private Long videoDuration;
|
||||||
|
private Integer videoWidth;
|
||||||
|
private Integer videoHeight;
|
||||||
|
private Integer videoBitRate;
|
||||||
|
private String videoEncoder;
|
||||||
|
private Float videoFrameRate;
|
||||||
|
private Long audioDuration;
|
||||||
|
private Integer audioBitRate;
|
||||||
|
private Long audioSampleRate;
|
||||||
|
private String convertStatus;
|
||||||
|
private String gmtCreate;
|
||||||
|
|
||||||
|
public String getKeyframe() {
|
||||||
|
return keyframe == null ? "" : keyframe;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyframe(String keyframe) {
|
||||||
|
this.keyframe = keyframe;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getVideoDuration() {
|
||||||
|
return videoDuration == null ? 0 : videoDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVideoDuration(Long videoDuration) {
|
||||||
|
this.videoDuration = videoDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getVideoWidth() {
|
||||||
|
return videoWidth == null ? 0 : videoWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVideoWidth(Integer videoWidth) {
|
||||||
|
this.videoWidth = videoWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getVideoHeight() {
|
||||||
|
return videoHeight == null ? 0 : videoHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVideoHeight(Integer videoHeight) {
|
||||||
|
this.videoHeight = videoHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getVideoBitRate() {
|
||||||
|
return videoBitRate == null ? 0 : videoBitRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVideoBitRate(Integer videoBitRate) {
|
||||||
|
this.videoBitRate = videoBitRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVideoEncoder() {
|
||||||
|
return videoEncoder == null ? "" : videoEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVideoEncoder(String videoEncoder) {
|
||||||
|
this.videoEncoder = videoEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getVideoFrameRate() {
|
||||||
|
return videoFrameRate == null ? 0 : videoFrameRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVideoFrameRate(Float videoFrameRate) {
|
||||||
|
this.videoFrameRate = videoFrameRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAudioDuration() {
|
||||||
|
return audioDuration == null ? 0 : audioDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAudioDuration(Long audioDuration) {
|
||||||
|
this.audioDuration = audioDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getAudioBitRate() {
|
||||||
|
return audioBitRate == null ? 0 : audioBitRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAudioBitRate(Integer audioBitRate) {
|
||||||
|
this.audioBitRate = audioBitRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAudioSampleRate() {
|
||||||
|
return audioSampleRate == null ? 0 : audioSampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAudioSampleRate(Long audioSampleRate) {
|
||||||
|
this.audioSampleRate = audioSampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConvertStatus() {
|
||||||
|
return convertStatus == null ? "" : convertStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConvertStatus(String convertStatus) {
|
||||||
|
this.convertStatus = convertStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGmtCreate() {
|
||||||
|
return gmtCreate == null ? "" : gmtCreate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGmtCreate(String gmtCreate) {
|
||||||
|
this.gmtCreate = gmtCreate;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,9 @@
|
|||||||
package ink.wgink.module.file.media.pojo.vos;
|
package ink.wgink.module.file.media.pojo.vos;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When you feel like quitting. Think about why you started
|
* When you feel like quitting. Think about why you started
|
||||||
* 当你想要放弃的时候,想想当初你为何开始
|
* 当你想要放弃的时候,想想当初你为何开始
|
||||||
@ -20,6 +24,8 @@ public class MediaVO {
|
|||||||
private Long fileSize;
|
private Long fileSize;
|
||||||
private String fileSummary;
|
private String fileSummary;
|
||||||
private String fileMd5;
|
private String fileMd5;
|
||||||
|
private Integer isBack;
|
||||||
|
private String staticUrl;
|
||||||
|
|
||||||
public String getFileName() {
|
public String getFileName() {
|
||||||
return fileName == null ? "" : fileName.trim();
|
return fileName == null ? "" : fileName.trim();
|
||||||
@ -84,4 +90,20 @@ public class MediaVO {
|
|||||||
public void setFileMd5(String fileMd5) {
|
public void setFileMd5(String fileMd5) {
|
||||||
this.fileMd5 = fileMd5;
|
this.fileMd5 = fileMd5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getIsBack() {
|
||||||
|
return isBack == null ? 0 : isBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsBack(Integer isBack) {
|
||||||
|
this.isBack = isBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStaticUrl() {
|
||||||
|
return staticUrl == null ? "" : staticUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStaticUrl(String staticUrl) {
|
||||||
|
this.staticUrl = staticUrl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,74 +15,75 @@ import ink.wgink.module.file.media.pojo.vos.MediaVO;
|
|||||||
public class VideoVO extends MediaVO {
|
public class VideoVO extends MediaVO {
|
||||||
|
|
||||||
private String keyframe;
|
private String keyframe;
|
||||||
private Long duration;
|
private Long videoDuration;
|
||||||
private Integer width;
|
private Integer videoWidth;
|
||||||
private Integer height;
|
private Integer videoHeight;
|
||||||
private Integer bitRate;
|
private Integer videoBitRate;
|
||||||
private String encoder;
|
private String videoEncoder;
|
||||||
private Float frameRate;
|
private Float videoFrameRate;
|
||||||
private Long audioDuration;
|
private Long audioDuration;
|
||||||
private Integer audioBitRate;
|
private Integer audioBitRate;
|
||||||
private Long audioSampleRate;
|
private Long audioSampleRate;
|
||||||
|
private String convertStatus;
|
||||||
|
|
||||||
public String getKeyframe() {
|
public String getKeyframe() {
|
||||||
return keyframe == null ? "" : keyframe.trim();
|
return keyframe == null ? "" : keyframe;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setKeyframe(String keyframe) {
|
public void setKeyframe(String keyframe) {
|
||||||
this.keyframe = keyframe;
|
this.keyframe = keyframe;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getDuration() {
|
public Long getVideoDuration() {
|
||||||
return duration;
|
return videoDuration == null ? 0 : videoDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDuration(Long duration) {
|
public void setVideoDuration(Long videoDuration) {
|
||||||
this.duration = duration;
|
this.videoDuration = videoDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getWidth() {
|
public Integer getVideoWidth() {
|
||||||
return width;
|
return videoWidth == null ? 0 : videoWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWidth(Integer width) {
|
public void setVideoWidth(Integer videoWidth) {
|
||||||
this.width = width;
|
this.videoWidth = videoWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getHeight() {
|
public Integer getVideoHeight() {
|
||||||
return height;
|
return videoHeight == null ? 0 : videoHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHeight(Integer height) {
|
public void setVideoHeight(Integer videoHeight) {
|
||||||
this.height = height;
|
this.videoHeight = videoHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getBitRate() {
|
public Integer getVideoBitRate() {
|
||||||
return bitRate;
|
return videoBitRate == null ? 0 : videoBitRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBitRate(Integer bitRate) {
|
public void setVideoBitRate(Integer videoBitRate) {
|
||||||
this.bitRate = bitRate;
|
this.videoBitRate = videoBitRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEncoder() {
|
public String getVideoEncoder() {
|
||||||
return encoder == null ? "" : encoder.trim();
|
return videoEncoder == null ? "" : videoEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEncoder(String encoder) {
|
public void setVideoEncoder(String videoEncoder) {
|
||||||
this.encoder = encoder;
|
this.videoEncoder = videoEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Float getFrameRate() {
|
public Float getVideoFrameRate() {
|
||||||
return frameRate;
|
return videoFrameRate == null ? 0 : videoFrameRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFrameRate(Float frameRate) {
|
public void setVideoFrameRate(Float videoFrameRate) {
|
||||||
this.frameRate = frameRate;
|
this.videoFrameRate = videoFrameRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getAudioDuration() {
|
public Long getAudioDuration() {
|
||||||
return audioDuration;
|
return audioDuration == null ? 0 : audioDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAudioDuration(Long audioDuration) {
|
public void setAudioDuration(Long audioDuration) {
|
||||||
@ -90,7 +91,7 @@ public class VideoVO extends MediaVO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Integer getAudioBitRate() {
|
public Integer getAudioBitRate() {
|
||||||
return audioBitRate;
|
return audioBitRate == null ? 0 : audioBitRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAudioBitRate(Integer audioBitRate) {
|
public void setAudioBitRate(Integer audioBitRate) {
|
||||||
@ -98,10 +99,18 @@ public class VideoVO extends MediaVO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Long getAudioSampleRate() {
|
public Long getAudioSampleRate() {
|
||||||
return audioSampleRate;
|
return audioSampleRate == null ? 0 : audioSampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAudioSampleRate(Long audioSampleRate) {
|
public void setAudioSampleRate(Long audioSampleRate) {
|
||||||
this.audioSampleRate = audioSampleRate;
|
this.audioSampleRate = audioSampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getConvertStatus() {
|
||||||
|
return convertStatus == null ? "" : convertStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConvertStatus(String convertStatus) {
|
||||||
|
this.convertStatus = convertStatus;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,17 @@
|
|||||||
package ink.wgink.module.file.media.service.video;
|
package ink.wgink.module.file.media.service.video;
|
||||||
|
|
||||||
|
import ink.wgink.exceptions.SearchException;
|
||||||
|
import ink.wgink.module.file.media.pojo.dtos.ConvertProgressDTO;
|
||||||
|
import ink.wgink.module.file.media.pojo.dtos.video.VideoDTO;
|
||||||
import ink.wgink.module.file.media.pojo.vos.video.VideoVO;
|
import ink.wgink.module.file.media.pojo.vos.video.VideoVO;
|
||||||
|
import ink.wgink.pojo.ListPage;
|
||||||
|
import ink.wgink.pojo.result.SuccessResultList;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When you feel like quitting. Think about why you started
|
* When you feel like quitting. Think about why you started
|
||||||
@ -34,6 +44,35 @@ public interface IVideoService {
|
|||||||
*/
|
*/
|
||||||
String save(String token, VideoVO videoVO);
|
String save(String token, VideoVO videoVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
*
|
||||||
|
* @param ids
|
||||||
|
*/
|
||||||
|
void remove(List<String> ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除(物理)
|
||||||
|
*
|
||||||
|
* @param ids
|
||||||
|
*/
|
||||||
|
void delete(List<String> ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新转码信息
|
||||||
|
*
|
||||||
|
* @param fileId
|
||||||
|
*/
|
||||||
|
void updateConvert(String fileId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新转码信息
|
||||||
|
*
|
||||||
|
* @param fileId 文件ID
|
||||||
|
* @param convertFile 转码文件
|
||||||
|
*/
|
||||||
|
void updateConvert(String fileId, File convertFile);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传视频
|
* 上传视频
|
||||||
*
|
*
|
||||||
@ -50,4 +89,52 @@ public interface IVideoService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
String upload(String token, MultipartFile video);
|
String upload(String token, MultipartFile video);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换进度列表
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
SseEmitter getConvertProgress();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 详情
|
||||||
|
*
|
||||||
|
* @param params
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
VideoDTO get(Map<String, Object> params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 详情
|
||||||
|
*
|
||||||
|
* @param fileId 文件ID
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
VideoDTO get(String fileId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 详情
|
||||||
|
*
|
||||||
|
* @param fileMd5 文件MD5值
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
VideoDTO getByMd5(String fileMd5);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表
|
||||||
|
*
|
||||||
|
* @param params
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<VideoDTO> list(Map<String, Object> params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页
|
||||||
|
*
|
||||||
|
* @param page
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
SuccessResultList<List<VideoDTO>> listPage(ListPage page);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,39 @@
|
|||||||
package ink.wgink.module.file.media.service.video.impl;
|
package ink.wgink.module.file.media.service.video.impl;
|
||||||
|
|
||||||
|
import com.github.pagehelper.PageHelper;
|
||||||
|
import com.github.pagehelper.PageInfo;
|
||||||
import ink.wgink.common.base.DefaultBaseService;
|
import ink.wgink.common.base.DefaultBaseService;
|
||||||
import ink.wgink.exceptions.FileException;
|
import ink.wgink.exceptions.FileException;
|
||||||
|
import ink.wgink.exceptions.SearchException;
|
||||||
|
import ink.wgink.module.file.media.dao.video.IVideoDao;
|
||||||
|
import ink.wgink.module.file.media.enums.ConvertStatusEnum;
|
||||||
import ink.wgink.module.file.media.manager.MediaManager;
|
import ink.wgink.module.file.media.manager.MediaManager;
|
||||||
import ink.wgink.module.file.media.manager.domain.MusicMetaInfo;
|
import ink.wgink.module.file.media.manager.domain.MusicMetaInfo;
|
||||||
import ink.wgink.module.file.media.manager.domain.VideoMetaInfo;
|
import ink.wgink.module.file.media.manager.domain.VideoMetaInfo;
|
||||||
|
import ink.wgink.module.file.media.pojo.dtos.ConvertProgressDTO;
|
||||||
|
import ink.wgink.module.file.media.pojo.dtos.video.VideoDTO;
|
||||||
import ink.wgink.module.file.media.pojo.vos.video.VideoVO;
|
import ink.wgink.module.file.media.pojo.vos.video.VideoVO;
|
||||||
import ink.wgink.module.file.media.service.IMediaService;
|
import ink.wgink.module.file.media.service.IMediaService;
|
||||||
import ink.wgink.module.file.media.service.video.IVideoService;
|
import ink.wgink.module.file.media.service.video.IVideoService;
|
||||||
|
import ink.wgink.module.file.media.task.transcoding.VideoConvertManager;
|
||||||
|
import ink.wgink.module.file.media.task.transcoding.runnable.VideoConvertRunnable;
|
||||||
|
import ink.wgink.pojo.ListPage;
|
||||||
|
import ink.wgink.pojo.result.SuccessResultList;
|
||||||
import ink.wgink.properties.media.MediaProperties;
|
import ink.wgink.properties.media.MediaProperties;
|
||||||
import ink.wgink.util.UUIDUtil;
|
import ink.wgink.util.UUIDUtil;
|
||||||
|
import ink.wgink.util.date.DateUtil;
|
||||||
|
import ink.wgink.util.map.HashMapUtil;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When you feel like quitting. Think about why you started
|
* When you feel like quitting. Think about why you started
|
||||||
@ -33,17 +52,99 @@ public class VideoServiceImpl extends DefaultBaseService implements IVideoServic
|
|||||||
private IMediaService mediaService;
|
private IMediaService mediaService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private MediaProperties mediaProperties;
|
private MediaProperties mediaProperties;
|
||||||
|
@Autowired
|
||||||
|
private IVideoDao videoDao;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String save(VideoVO videoVO) {
|
public String save(VideoVO videoVO) {
|
||||||
return null;
|
return save(null, videoVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String save(String token, VideoVO videoVO) {
|
public String save(String token, VideoVO videoVO) {
|
||||||
String fileId = UUIDUtil.getUUID();
|
String fileId = UUIDUtil.getUUID();
|
||||||
|
Map<String, Object> params = HashMapUtil.beanToMap(videoVO);
|
||||||
|
params.put("fileId", fileId);
|
||||||
|
if (StringUtils.isBlank(token)) {
|
||||||
|
setSaveInfo(params);
|
||||||
|
} else {
|
||||||
|
setAppSaveInfo(token, params);
|
||||||
|
}
|
||||||
|
videoDao.save(params);
|
||||||
|
return fileId;
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
@Override
|
||||||
|
public void remove(List<String> ids) {
|
||||||
|
Map<String, Object> params = getHashMap(2);
|
||||||
|
params.put("fileIds", ids);
|
||||||
|
List<VideoDTO> videoDTOs = videoDao.list(params);
|
||||||
|
checkConverting(videoDTOs);
|
||||||
|
setUpdateInfo(params);
|
||||||
|
videoDao.remove(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(List<String> ids) {
|
||||||
|
Map<String, Object> params = getHashMap(2);
|
||||||
|
params.put("fileIds", ids);
|
||||||
|
List<VideoDTO> videoDTOs = videoDao.list(params);
|
||||||
|
checkConverting(videoDTOs);
|
||||||
|
// 删除文件
|
||||||
|
for (VideoDTO videoDTO : videoDTOs) {
|
||||||
|
deleteSourceFile(videoDTO.getFileFullPath());
|
||||||
|
}
|
||||||
|
// 删除记录
|
||||||
|
videoDao.delete(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateConvert(String fileId) {
|
||||||
|
VideoDTO videoDTO = get(fileId);
|
||||||
|
if (videoDTO == null) {
|
||||||
|
throw new SearchException("视频不存在");
|
||||||
|
}
|
||||||
|
VideoConvertManager.getInstance().convert(new VideoConvertRunnable(fileId, videoDTO.getFileFullPath(), this));
|
||||||
|
// 更新状态
|
||||||
|
Map<String, Object> params = getHashMap(8);
|
||||||
|
params.put("convertStatus", ConvertStatusEnum.CONVERTING.getValue());
|
||||||
|
params.put("fileId", fileId);
|
||||||
|
setUpdateInfo(params);
|
||||||
|
videoDao.updateConvert(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateConvert(String fileId, File convertFile) {
|
||||||
|
VideoDTO videoDTO = get(fileId);
|
||||||
|
if (videoDTO == null) {
|
||||||
|
throw new SearchException("视频不存在");
|
||||||
|
}
|
||||||
|
Map<String, Object> params = getHashMap(10);
|
||||||
|
params.put("fileSize", convertFile.length());
|
||||||
|
params.put("fileType", "mp4");
|
||||||
|
params.put("fileName", convertFile.getName());
|
||||||
|
params.put("fileFullPath", convertFile.getAbsolutePath());
|
||||||
|
|
||||||
|
VideoMetaInfo videoMetaInfo = MediaManager.getInstance().getVideoMetaInfo(convertFile);
|
||||||
|
params.put("videoDuration", videoMetaInfo.getDuration());
|
||||||
|
params.put("videoWidth", videoMetaInfo.getWidth());
|
||||||
|
params.put("videoHeight", videoMetaInfo.getHeight());
|
||||||
|
params.put("videoBitRate", videoMetaInfo.getBitRate());
|
||||||
|
params.put("videoEncoder", videoMetaInfo.getEncoder());
|
||||||
|
params.put("videoFrameRate", videoMetaInfo.getFrameRate());
|
||||||
|
params.put("convertStatus", ConvertStatusEnum.CONVERTED.getValue());
|
||||||
|
|
||||||
|
MusicMetaInfo musicMetaInfo = videoMetaInfo.getMusicMetaInfo();
|
||||||
|
if (musicMetaInfo != null) {
|
||||||
|
params.put("audioDuration", musicMetaInfo.getDuration());
|
||||||
|
params.put("audioBitRate", musicMetaInfo.getBitRate());
|
||||||
|
params.put("audioSampleRate", musicMetaInfo.getSampleRate());
|
||||||
|
}
|
||||||
|
params.put("fileId", fileId);
|
||||||
|
setUpdateInfoByUserId(params, "1");
|
||||||
|
videoDao.update(params);
|
||||||
|
// 删除源文件
|
||||||
|
deleteSourceFile(videoDTO.getFileFullPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -53,32 +154,44 @@ public class VideoServiceImpl extends DefaultBaseService implements IVideoServic
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String upload(String token, MultipartFile video) {
|
public String upload(String token, MultipartFile video) {
|
||||||
String filePath = mediaProperties.getUploadPath() + File.separator + VIDEO_PATH;
|
String filePath = VIDEO_PATH + File.separator + DateUtil.getDays();
|
||||||
|
String uploadFolderPath = mediaProperties.getUploadPath() + File.separator + filePath;
|
||||||
String fileName = video.getOriginalFilename();
|
String fileName = video.getOriginalFilename();
|
||||||
long fileSize = video.getSize();
|
long fileSize = video.getSize();
|
||||||
String fileType = mediaService.getFileType(fileName);
|
String fileType = mediaService.getFileType(fileName);
|
||||||
String fileMd5 = mediaService.upload(video, filePath, fileName);
|
String uuidFileName = UUIDUtil.getUUID() + "." + fileType;
|
||||||
String fileFullPath = filePath;
|
String fileMd5 = mediaService.upload(video, uploadFolderPath, uuidFileName);
|
||||||
|
// 判断文件是否存在,已经存在的不再新增,直接返回结果,删除临时文件
|
||||||
|
VideoDTO videoDTO = getByMd5(fileMd5);
|
||||||
|
String fileFullPath = uploadFolderPath + File.separator + uuidFileName;
|
||||||
|
File uploadFile = new File(fileFullPath);
|
||||||
|
if (videoDTO != null) {
|
||||||
|
LOG.error("上传的【{}】视频已经存在,原文件为【{}】,返回原文件ID", videoDTO.getFileName(), videoDTO.getFileName());
|
||||||
|
uploadFile.delete();
|
||||||
|
return videoDTO.getFileId();
|
||||||
|
}
|
||||||
|
|
||||||
// 构建视频内容
|
// 构建视频内容
|
||||||
VideoVO videoVO = new VideoVO();
|
VideoVO videoVO = new VideoVO();
|
||||||
videoVO.setFileName(fileName);
|
videoVO.setFileName(fileName);
|
||||||
videoVO.setFileFullPath(fileFullPath);
|
videoVO.setFileFullPath(fileFullPath);
|
||||||
videoVO.setFilePath(VIDEO_PATH);
|
videoVO.setFilePath(filePath);
|
||||||
videoVO.setFileSize(fileSize);
|
videoVO.setFileSize(fileSize);
|
||||||
videoVO.setFileType(fileType);
|
videoVO.setFileType(fileType);
|
||||||
videoVO.setFileMd5(fileMd5);
|
videoVO.setFileMd5(fileMd5);
|
||||||
|
videoVO.setIsBack(0);
|
||||||
|
|
||||||
File uploadFile = new File(fileFullPath + File.separator + fileName);
|
|
||||||
VideoMetaInfo videoMetaInfo = MediaManager.getInstance().getVideoMetaInfo(uploadFile);
|
VideoMetaInfo videoMetaInfo = MediaManager.getInstance().getVideoMetaInfo(uploadFile);
|
||||||
if (videoMetaInfo == null) {
|
if (videoMetaInfo == null) {
|
||||||
throw new FileException("上传失败");
|
throw new FileException("上传失败");
|
||||||
}
|
}
|
||||||
videoVO.setDuration(videoMetaInfo.getDuration());
|
videoVO.setVideoDuration(videoMetaInfo.getDuration());
|
||||||
videoVO.setWidth(videoMetaInfo.getWidth());
|
videoVO.setVideoWidth(videoMetaInfo.getWidth());
|
||||||
videoVO.setHeight(videoMetaInfo.getHeight());
|
videoVO.setVideoHeight(videoMetaInfo.getHeight());
|
||||||
videoVO.setBitRate(videoMetaInfo.getBitRate());
|
videoVO.setVideoBitRate(videoMetaInfo.getBitRate());
|
||||||
videoVO.setEncoder(videoMetaInfo.getEncoder());
|
videoVO.setVideoEncoder(videoMetaInfo.getEncoder());
|
||||||
videoVO.setFrameRate(videoMetaInfo.getFrameRate());
|
videoVO.setVideoFrameRate(videoMetaInfo.getFrameRate());
|
||||||
|
videoVO.setConvertStatus(ConvertStatusEnum.UN_CONVERTED.getValue());
|
||||||
|
|
||||||
MusicMetaInfo musicMetaInfo = videoMetaInfo.getMusicMetaInfo();
|
MusicMetaInfo musicMetaInfo = videoMetaInfo.getMusicMetaInfo();
|
||||||
if (musicMetaInfo != null) {
|
if (musicMetaInfo != null) {
|
||||||
@ -86,9 +199,84 @@ public class VideoServiceImpl extends DefaultBaseService implements IVideoServic
|
|||||||
videoVO.setAudioBitRate(musicMetaInfo.getBitRate());
|
videoVO.setAudioBitRate(musicMetaInfo.getBitRate());
|
||||||
videoVO.setAudioSampleRate(musicMetaInfo.getSampleRate());
|
videoVO.setAudioSampleRate(musicMetaInfo.getSampleRate());
|
||||||
}
|
}
|
||||||
String fileId = save(token, videoVO);
|
return save(token, videoVO);
|
||||||
// 转码
|
}
|
||||||
return fileId;
|
|
||||||
|
@Override
|
||||||
|
public SseEmitter getConvertProgress() {
|
||||||
|
String threadId = String.valueOf(Thread.currentThread().getId());
|
||||||
|
// 30分钟超时
|
||||||
|
SseEmitter sseEmitter = new SseEmitter(1800000L);
|
||||||
|
sseEmitter.onTimeout(() -> {
|
||||||
|
VideoConvertManager.getInstance().removeConvertProgressSseEmitter(threadId);
|
||||||
|
});
|
||||||
|
sseEmitter.onCompletion(() -> {
|
||||||
|
});
|
||||||
|
sseEmitter.onError(throwable -> {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
});
|
||||||
|
VideoConvertManager.getInstance().addConvertProgressSseEmitter(threadId, sseEmitter);
|
||||||
|
return sseEmitter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VideoDTO get(Map<String, Object> params) {
|
||||||
|
return videoDao.get(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VideoDTO get(String fileId) {
|
||||||
|
Map<String, Object> params = getHashMap(2);
|
||||||
|
params.put("fileId", fileId);
|
||||||
|
return get(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VideoDTO getByMd5(String fileMd5) {
|
||||||
|
Map<String, Object> params = getHashMap(2);
|
||||||
|
params.put("fileMd5", fileMd5);
|
||||||
|
return get(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<VideoDTO> list(Map<String, Object> params) {
|
||||||
|
return videoDao.list(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SuccessResultList<List<VideoDTO>> listPage(ListPage page) {
|
||||||
|
PageHelper.startPage(page.getPage(), page.getRows());
|
||||||
|
List<VideoDTO> videoDTOs = list(page.getParams());
|
||||||
|
PageInfo<VideoDTO> pageInfo = new PageInfo<>(videoDTOs);
|
||||||
|
return new SuccessResultList<>(videoDTOs, pageInfo.getPageNum(), pageInfo.getTotal());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查转换中状态
|
||||||
|
*/
|
||||||
|
private void checkConverting(List<VideoDTO> videoDTOs) {
|
||||||
|
for (VideoDTO videoDTO : videoDTOs) {
|
||||||
|
if (StringUtils.equals(ConvertStatusEnum.CONVERTING.getValue(), videoDTO.getConvertStatus())) {
|
||||||
|
throw new SearchException("存在转码中的视频,删除失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除源文件
|
||||||
|
*
|
||||||
|
* @param sourceFilePath 源文件路径
|
||||||
|
*/
|
||||||
|
private void deleteSourceFile(String sourceFilePath) {
|
||||||
|
File file = new File(sourceFilePath);
|
||||||
|
if (file.exists()) {
|
||||||
|
boolean isDelete = file.delete();
|
||||||
|
if (isDelete) {
|
||||||
|
LOG.debug("源文件删除成功");
|
||||||
|
} else {
|
||||||
|
LOG.debug("源文件删除失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,62 @@
|
|||||||
|
package ink.wgink.module.file.media.task.transcoding;
|
||||||
|
|
||||||
|
import ink.wgink.module.file.media.pojo.dtos.ConvertProgressDTO;
|
||||||
|
import ink.wgink.module.file.media.task.transcoding.runnable.VideoConvertRunnable;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When you feel like quitting. Think about why you started
|
||||||
|
* 当你想要放弃的时候,想想当初你为何开始
|
||||||
|
*
|
||||||
|
* @ClassName: VideoTransCodingManager
|
||||||
|
* @Description: 视频转码
|
||||||
|
* @Author: wanggeng
|
||||||
|
* @Date: 2021/6/10 9:46 上午
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class VideoConvertManager {
|
||||||
|
|
||||||
|
private static VideoConvertManager VIDEO_TRANS_CODING_MANAGER = VideoTransCodingManagerBuilder.videoConvertManager;
|
||||||
|
private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 10, 30L, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
|
||||||
|
private Map<String, SseEmitter> convertProgressSseEmitterMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private VideoConvertManager() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VideoConvertManager getInstance() {
|
||||||
|
return VIDEO_TRANS_CODING_MANAGER;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void convert(VideoConvertRunnable videoConvertRunnable) {
|
||||||
|
threadPoolExecutor.execute(videoConvertRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addConvertProgressSseEmitter(String threadId, SseEmitter sseEmitter) {
|
||||||
|
convertProgressSseEmitterMap.put(threadId, sseEmitter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeConvertProgressSseEmitter(String threadId) {
|
||||||
|
convertProgressSseEmitterMap.remove(threadId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void convertProgressSseEmitterNotice(String fileId, Double percent) {
|
||||||
|
ConvertProgressDTO convertProgressDTO = new ConvertProgressDTO();
|
||||||
|
convertProgressDTO.setFileId(fileId);
|
||||||
|
convertProgressDTO.setPercent(percent);
|
||||||
|
try {
|
||||||
|
for (Map.Entry<String, SseEmitter> kv : convertProgressSseEmitterMap.entrySet()) {
|
||||||
|
kv.getValue().send(convertProgressDTO);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class VideoTransCodingManagerBuilder {
|
||||||
|
public static VideoConvertManager videoConvertManager = new VideoConvertManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,31 +0,0 @@
|
|||||||
package ink.wgink.module.file.media.task.transcoding;
|
|
||||||
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.LinkedBlockingDeque;
|
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When you feel like quitting. Think about why you started
|
|
||||||
* 当你想要放弃的时候,想想当初你为何开始
|
|
||||||
*
|
|
||||||
* @ClassName: VideoTransCodingManager
|
|
||||||
* @Description: 视频转码
|
|
||||||
* @Author: wanggeng
|
|
||||||
* @Date: 2021/6/10 9:46 上午
|
|
||||||
* @Version: 1.0
|
|
||||||
*/
|
|
||||||
public class VideoTransCodingManager {
|
|
||||||
|
|
||||||
private static VideoTransCodingManager VIDEO_TRANS_CODING_MANAGER = VideoTransCodingManagerBuilder.videoTransCodingManager;
|
|
||||||
private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 10, 30L, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
|
|
||||||
|
|
||||||
private VideoTransCodingManager() {}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static class VideoTransCodingManagerBuilder {
|
|
||||||
public static VideoTransCodingManager videoTransCodingManager = new VideoTransCodingManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,126 @@
|
|||||||
|
package ink.wgink.module.file.media.task.transcoding.runnable;
|
||||||
|
|
||||||
|
import ink.wgink.module.file.media.manager.MediaManager;
|
||||||
|
import ink.wgink.module.file.media.manager.domain.enums.CrfValueEnum;
|
||||||
|
import ink.wgink.module.file.media.manager.domain.enums.PresetVauleEnum;
|
||||||
|
import ink.wgink.module.file.media.manager.process.IMediaStream;
|
||||||
|
import ink.wgink.module.file.media.service.video.IVideoService;
|
||||||
|
import ink.wgink.module.file.media.task.transcoding.VideoConvertManager;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When you feel like quitting. Think about why you started
|
||||||
|
* 当你想要放弃的时候,想想当初你为何开始
|
||||||
|
*
|
||||||
|
* @ClassName: VideoTransCodingRunnable
|
||||||
|
* @Description: 视频转码
|
||||||
|
* @Author: wanggeng
|
||||||
|
* @Date: 2021/6/10 10:04 上午
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class VideoConvertRunnable implements Runnable {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(VideoConvertRunnable.class);
|
||||||
|
private static Pattern durationPattern = Pattern.compile("Duration: \\d{2}:\\d{2}:\\d{2}");
|
||||||
|
private static Pattern timePattern = Pattern.compile("time=\\d{2}:\\d{2}:\\d{2}");
|
||||||
|
|
||||||
|
private long fullTime = 0L;
|
||||||
|
private long currentTime = 0L;
|
||||||
|
private double convertPercent = 0D;
|
||||||
|
private boolean isUpdateConvertStatus = false;
|
||||||
|
private File outFile;
|
||||||
|
|
||||||
|
private String fileId;
|
||||||
|
private String sourceFile;
|
||||||
|
private IVideoService videoService;
|
||||||
|
|
||||||
|
public VideoConvertRunnable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public VideoConvertRunnable(String fileId, String sourceFile, IVideoService videoService) {
|
||||||
|
this.fileId = fileId;
|
||||||
|
this.sourceFile = sourceFile;
|
||||||
|
this.videoService = videoService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
File sourceFile = new File(this.sourceFile);
|
||||||
|
outFile = new File(this.sourceFile + ".mp4");
|
||||||
|
MediaManager.getInstance().convertVideo(sourceFile, outFile, true, CrfValueEnum.HIGH_QUALITY.getCode(), PresetVauleEnum.MAX_FAST_ZIP_SPEED.getPresetValue(), null, null, new IMediaStream() {
|
||||||
|
@Override
|
||||||
|
public void input(InputStream inputStream) throws Exception {
|
||||||
|
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
|
||||||
|
for (String line; (line = bufferedReader.readLine()) != null; ) {
|
||||||
|
LOG.debug(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(InputStream errorStream) throws Exception {
|
||||||
|
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(errorStream));
|
||||||
|
for (String line; (line = bufferedReader.readLine()) != null; ) {
|
||||||
|
Matcher durationMatcher = durationPattern.matcher(line);
|
||||||
|
Matcher timeMatcher = timePattern.matcher(line);
|
||||||
|
if (durationMatcher.find()) {
|
||||||
|
String duration = durationMatcher.group();
|
||||||
|
LOG.debug("开始转码,时长:{}", duration);
|
||||||
|
String durationTime = duration.replace("Duration: ", "");
|
||||||
|
fullTime = durationToLongTime(durationTime);
|
||||||
|
}
|
||||||
|
if (timeMatcher.find()) {
|
||||||
|
String time = timeMatcher.group();
|
||||||
|
String timeTime = time.replace("time=", "");
|
||||||
|
currentTime = durationToLongTime(timeTime);
|
||||||
|
}
|
||||||
|
if (fullTime > 0L) {
|
||||||
|
convertPercent = new BigDecimal((currentTime / (fullTime * 1D) * 100D)).setScale(2, RoundingMode.HALF_UP).doubleValue();
|
||||||
|
}
|
||||||
|
if (convertPercent > 0D && convertPercent < 100D && (int) convertPercent % 5 == 0) {
|
||||||
|
VideoConvertManager.getInstance().convertProgressSseEmitterNotice(fileId, convertPercent);
|
||||||
|
}
|
||||||
|
if (convertPercent >= 100D) {
|
||||||
|
updateConvertStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新转换状态
|
||||||
|
*/
|
||||||
|
private void updateConvertStatus() {
|
||||||
|
if (isUpdateConvertStatus) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
VideoConvertManager.getInstance().convertProgressSseEmitterNotice(fileId, convertPercent);
|
||||||
|
isUpdateConvertStatus = true;
|
||||||
|
LOG.debug("转码结束,更新状态");
|
||||||
|
videoService.updateConvert(fileId, outFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频时长
|
||||||
|
*
|
||||||
|
* @param duration
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private long durationToLongTime(String duration) {
|
||||||
|
String[] durationArray = duration.split("\\:");
|
||||||
|
int hour = Integer.parseInt(durationArray[0]);
|
||||||
|
int minute = Integer.parseInt(durationArray[1]);
|
||||||
|
int second = Integer.parseInt(durationArray[2]);
|
||||||
|
return (hour * 3600 + minute * 60 + second);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,53 +0,0 @@
|
|||||||
package ink.wgink.module.file.media.task.transcoding.runnable;
|
|
||||||
|
|
||||||
import ink.wgink.module.file.media.manager.MediaManager;
|
|
||||||
import ink.wgink.module.file.media.manager.domain.enums.CrfValueEnum;
|
|
||||||
import ink.wgink.module.file.media.manager.domain.enums.PresetVauleEnum;
|
|
||||||
import ink.wgink.module.file.media.manager.process.IMediaStream;
|
|
||||||
import ink.wgink.module.file.media.service.video.IVideoService;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When you feel like quitting. Think about why you started
|
|
||||||
* 当你想要放弃的时候,想想当初你为何开始
|
|
||||||
*
|
|
||||||
* @ClassName: VideoTransCodingRunnable
|
|
||||||
* @Description: 视频转码
|
|
||||||
* @Author: wanggeng
|
|
||||||
* @Date: 2021/6/10 10:04 上午
|
|
||||||
* @Version: 1.0
|
|
||||||
*/
|
|
||||||
public class VideoTransCodingRunnable implements Runnable {
|
|
||||||
|
|
||||||
private String sourcePath;
|
|
||||||
private String sourceName;
|
|
||||||
private IVideoService videoService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
File sourceFile = new File(sourcePath + File.separator + sourceName);
|
|
||||||
File outFile = new File(sourcePath + File.separator + sourceName + ".mp4");
|
|
||||||
MediaManager.getInstance().convertVideo(sourceFile, outFile, true, CrfValueEnum.HIGH_QUALITY.getCode(), PresetVauleEnum.MAX_FAST_ZIP_SPEED.getPresetValue(), null, null, new IMediaStream() {
|
|
||||||
@Override
|
|
||||||
public void input(InputStream inputStream) throws Exception {
|
|
||||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
|
|
||||||
for (String line; (line = bufferedReader.readLine()) != null; ) {
|
|
||||||
System.out.println("input-" + line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void error(InputStream errorStream) throws Exception {
|
|
||||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(errorStream));
|
|
||||||
for (String line; (line = bufferedReader.readLine()) != null; ) {
|
|
||||||
System.out.println("error-" + line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,298 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="ink.wgink.module.file.media.dao.video.IVideoDao">
|
||||||
|
|
||||||
|
<cache/>
|
||||||
|
|
||||||
|
<resultMap id="videoDTO" type="ink.wgink.module.file.media.pojo.dtos.video.VideoDTO">
|
||||||
|
<id column="file_id" property="fileId"/>
|
||||||
|
<result column="file_name" property="fileName"/>
|
||||||
|
<result column="file_full_path" property="fileFullPath"/>
|
||||||
|
<result column="file_path" property="filePath"/>
|
||||||
|
<result column="file_size" property="fileSize"/>
|
||||||
|
<result column="file_type" property="fileType"/>
|
||||||
|
<result column="file_md5" property="fileMd5"/>
|
||||||
|
<result column="is_back" property="isBack"/>
|
||||||
|
<result column="static_url" property="staticUrl"/>
|
||||||
|
<result column="file_summary" property="fileSummary"/>
|
||||||
|
<result column="video_duration" property="videoDuration"/>
|
||||||
|
<result column="video_width" property="videoWidth"/>
|
||||||
|
<result column="video_height" property="videoHeight"/>
|
||||||
|
<result column="video_bit_rate" property="videoBitRate"/>
|
||||||
|
<result column="video_encoder" property="videoEncoder"/>
|
||||||
|
<result column="video_frame_rate" property="videoFrameRate"/>
|
||||||
|
<result column="audio_duration" property="audioDuration"/>
|
||||||
|
<result column="audio_bit_rate" property="audioBitRate"/>
|
||||||
|
<result column="audio_sample_rate" property="audioSampleRate"/>
|
||||||
|
<result column="convert_status" property="convertStatus"/>
|
||||||
|
<result column="gmt_create" property="gmtCreate"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<!-- 建表 -->
|
||||||
|
<update id="createTable">
|
||||||
|
CREATE TABLE IF NOT EXISTS `media_video` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`file_id` char(36) NOT NULL COMMENT '主键',
|
||||||
|
`file_name` varchar(255) DEFAULT NULL COMMENT '名称',
|
||||||
|
`file_full_path` varchar(500) DEFAULT NULL COMMENT '全路径',
|
||||||
|
`file_path` varchar(255) DEFAULT NULL COMMENT '路径',
|
||||||
|
`file_size` varchar(100) DEFAULT NULL COMMENT '大小',
|
||||||
|
`file_type` varchar(255) DEFAULT NULL COMMENT '类型',
|
||||||
|
`file_md5` varchar(255) DEFAULT NULL COMMENT 'MD5',
|
||||||
|
`file_summary` varchar(255) DEFAULT NULL COMMENT '备注',
|
||||||
|
`video_duration` varchar(255) DEFAULT NULL COMMENT '时长',
|
||||||
|
`video_width` int(11) DEFAULT NULL COMMENT '宽度',
|
||||||
|
`video_height` int(11) DEFAULT NULL COMMENT '高度',
|
||||||
|
`video_bit_rate` int(11) DEFAULT NULL COMMENT '比特率',
|
||||||
|
`video_encoder` varchar(255) DEFAULT NULL COMMENT '编码',
|
||||||
|
`video_frame_rate` int(11) DEFAULT NULL COMMENT '帧率',
|
||||||
|
`audio_duration` varchar(255) DEFAULT NULL COMMENT '音频时长',
|
||||||
|
`audio_bit_rate` int(11) DEFAULT NULL COMMENT '音频比特率',
|
||||||
|
`audio_sample_rate` int(11) DEFAULT NULL COMMENT '音频采样率',
|
||||||
|
`convert_status` varchar(255) DEFAULT 'unConverted' COMMENT '转码状态',
|
||||||
|
`is_back` int(1) DEFAULT '0' COMMENT '是否备份',
|
||||||
|
`static_url` varchar(500) DEFAULT NULL COMMENT '静态url',
|
||||||
|
`creator` char(36) DEFAULT NULL COMMENT '创建人',
|
||||||
|
`gmt_create` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`modifier` char(36) DEFAULT NULL COMMENT '修改人',
|
||||||
|
`gmt_modified` datetime DEFAULT NULL COMMENT '修改时间',
|
||||||
|
`is_delete` int(1) DEFAULT '0',
|
||||||
|
PRIMARY KEY (`id`,`file_id`) USING BTREE,
|
||||||
|
UNIQUE KEY `file_id` (`file_id`) USING BTREE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<!-- 保存文件 -->
|
||||||
|
<insert id="save" parameterType="map" flushCache="true">
|
||||||
|
INSERT INTO media_video(
|
||||||
|
file_id,
|
||||||
|
file_name,
|
||||||
|
file_full_path,
|
||||||
|
file_path,
|
||||||
|
file_size,
|
||||||
|
file_type,
|
||||||
|
file_md5,
|
||||||
|
file_summary,
|
||||||
|
video_duration,
|
||||||
|
video_width,
|
||||||
|
video_height,
|
||||||
|
video_bit_rate,
|
||||||
|
video_encoder,
|
||||||
|
video_frame_rate,
|
||||||
|
audio_duration,
|
||||||
|
audio_bit_rate,
|
||||||
|
audio_sample_rate,
|
||||||
|
convert_status,
|
||||||
|
is_back,
|
||||||
|
static_url,
|
||||||
|
creator,
|
||||||
|
gmt_create,
|
||||||
|
modifier,
|
||||||
|
gmt_modified,
|
||||||
|
is_delete
|
||||||
|
) VALUES(
|
||||||
|
#{fileId},
|
||||||
|
#{fileName},
|
||||||
|
#{fileFullPath},
|
||||||
|
#{filePath},
|
||||||
|
#{fileSize},
|
||||||
|
#{fileType},
|
||||||
|
#{fileMd5},
|
||||||
|
#{fileSummary},
|
||||||
|
#{videoDuration},
|
||||||
|
#{videoWidth},
|
||||||
|
#{videoHeight},
|
||||||
|
#{videoBitRate},
|
||||||
|
#{videoEncoder},
|
||||||
|
#{videoFrameRate},
|
||||||
|
#{audioDuration},
|
||||||
|
#{audioBitRate},
|
||||||
|
#{audioSampleRate},
|
||||||
|
#{convertStatus},
|
||||||
|
#{isBack},
|
||||||
|
#{staticUrl},
|
||||||
|
#{creator},
|
||||||
|
#{gmtCreate},
|
||||||
|
#{modifier},
|
||||||
|
#{gmtModified},
|
||||||
|
#{isDelete}
|
||||||
|
)
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<!-- 删除文件 -->
|
||||||
|
<update id="remove" parameterType="map" flushCache="true">
|
||||||
|
UPDATE
|
||||||
|
media_video
|
||||||
|
SET
|
||||||
|
is_delete = 1,
|
||||||
|
modifier = #{modifier},
|
||||||
|
gmt_modified = #{gmtModified}
|
||||||
|
WHERE
|
||||||
|
file_id IN
|
||||||
|
<foreach collection="fileIds" index="index" open="(" separator="," close=")">
|
||||||
|
#{fileIds[${index}]}
|
||||||
|
</foreach>
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<!-- 删除文件(物理删除) -->
|
||||||
|
<delete id="delete" parameterType="map" flushCache="true">
|
||||||
|
DELETE FROM
|
||||||
|
media_video
|
||||||
|
WHERE
|
||||||
|
file_id IN
|
||||||
|
<foreach collection="fileIds" index="index" open="(" separator="," close=")">
|
||||||
|
#{fileIds[${index}]}
|
||||||
|
</foreach>
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<!-- 更新 -->
|
||||||
|
<update id="update" parameterType="map" flushCache="true">
|
||||||
|
UPDATE
|
||||||
|
media_video
|
||||||
|
SET
|
||||||
|
<if test="fileFullPath != null and fileFullPath != ''">
|
||||||
|
file_full_path = #{fileFullPath},
|
||||||
|
</if>
|
||||||
|
<if test="filePath != null and filePath != ''">
|
||||||
|
file_path = #{filePath},
|
||||||
|
</if>
|
||||||
|
<if test="fileSize != null and fileSize != ''">
|
||||||
|
file_size = #{fileSize},
|
||||||
|
</if>
|
||||||
|
<if test="fileType != null and fileType != ''">
|
||||||
|
file_type = #{fileType},
|
||||||
|
</if>
|
||||||
|
<if test="videoDuration != null and videoDuration != ''">
|
||||||
|
video_duration = #{videoDuration},
|
||||||
|
</if>
|
||||||
|
<if test="videoWidth != null">
|
||||||
|
video_width = #{videoWidth},
|
||||||
|
</if>
|
||||||
|
<if test="videoHeight != null">
|
||||||
|
video_height = #{videoHeight},
|
||||||
|
</if>
|
||||||
|
<if test="videoBitRate != null">
|
||||||
|
video_bit_rate = #{videoBitRate},
|
||||||
|
</if>
|
||||||
|
<if test="videoEncoder != null and videoEncoder != ''">
|
||||||
|
video_encoder = #{videoEncoder},
|
||||||
|
</if>
|
||||||
|
<if test="videoFrameRate != null">
|
||||||
|
video_frame_rate = #{videoFrameRate},
|
||||||
|
</if>
|
||||||
|
<if test="audioDuration != null and audioDuration != ''">
|
||||||
|
audio_duration = #{audioDuration},
|
||||||
|
</if>
|
||||||
|
<if test="audioBitRate != null">
|
||||||
|
audio_bit_rate = #{audioBitRate},
|
||||||
|
</if>
|
||||||
|
<if test="audioSampleRate != null">
|
||||||
|
audio_sample_rate = #{audioSampleRate},
|
||||||
|
</if>
|
||||||
|
<if test="convertStatus != null and convertStatus != ''">
|
||||||
|
convert_status = #{convertStatus},
|
||||||
|
</if>
|
||||||
|
modifier = #{modifier},
|
||||||
|
gmt_modified = #{gmtModified}
|
||||||
|
WHERE
|
||||||
|
file_id = #{fileId}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<!-- 更新转码状态 -->
|
||||||
|
<update id="updateConvert" parameterType="map" flushCache="true">
|
||||||
|
UPDATE
|
||||||
|
media_video
|
||||||
|
SET
|
||||||
|
convert_status = #{convertStatus},
|
||||||
|
modifier = #{modifier},
|
||||||
|
gmt_modified = #{gmtModified}
|
||||||
|
WHERE
|
||||||
|
file_id = #{fileId}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<!-- 详情 -->
|
||||||
|
<select id="get" parameterType="map" resultMap="videoDTO" useCache="true">
|
||||||
|
SELECT
|
||||||
|
file_id,
|
||||||
|
file_name,
|
||||||
|
file_full_path,
|
||||||
|
file_path,
|
||||||
|
file_size,
|
||||||
|
file_type,
|
||||||
|
file_md5,
|
||||||
|
file_summary,
|
||||||
|
video_duration,
|
||||||
|
video_width,
|
||||||
|
video_height,
|
||||||
|
video_bit_rate,
|
||||||
|
video_encoder,
|
||||||
|
video_frame_rate,
|
||||||
|
audio_duration,
|
||||||
|
audio_bit_rate,
|
||||||
|
audio_sample_rate,
|
||||||
|
convert_status,
|
||||||
|
is_back,
|
||||||
|
static_url
|
||||||
|
FROM
|
||||||
|
media_video
|
||||||
|
<where>
|
||||||
|
<if test="fileId != null and fileId != ''">
|
||||||
|
file_id = #{fileId}
|
||||||
|
</if>
|
||||||
|
<if test="fileMd5 != null and fileMd5 != ''">
|
||||||
|
AND file_md5 = #{fileMd5}
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 列表 -->
|
||||||
|
<select id="list" parameterType="map" resultMap="videoDTO" useCache="true">
|
||||||
|
SELECT
|
||||||
|
file_id,
|
||||||
|
file_name,
|
||||||
|
file_full_path,
|
||||||
|
file_path,
|
||||||
|
file_size,
|
||||||
|
file_type,
|
||||||
|
file_md5,
|
||||||
|
file_summary,
|
||||||
|
video_duration,
|
||||||
|
video_width,
|
||||||
|
video_height,
|
||||||
|
video_bit_rate,
|
||||||
|
video_encoder,
|
||||||
|
video_frame_rate,
|
||||||
|
audio_duration,
|
||||||
|
audio_bit_rate,
|
||||||
|
audio_sample_rate,
|
||||||
|
convert_status,
|
||||||
|
is_back,
|
||||||
|
static_url,
|
||||||
|
LEFT(gmt_create, 19) gmt_create
|
||||||
|
FROM
|
||||||
|
media_video
|
||||||
|
<where>
|
||||||
|
is_delete = 0
|
||||||
|
<if test="keywords != null and keywords != ''">
|
||||||
|
AND
|
||||||
|
file_name LIKE CONCAT('%', #{keywords}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="startTime != null and startTime != ''">
|
||||||
|
AND
|
||||||
|
LEFT(gmt_create, 10) <![CDATA[ >= ]]> #{startTime}
|
||||||
|
</if>
|
||||||
|
<if test="endTime != null and endTime != ''">
|
||||||
|
AND
|
||||||
|
LEFT(gmt_create, 10) <![CDATA[ <= ]]> #{endTime}
|
||||||
|
</if>
|
||||||
|
<if test="fileIds != null and fileIds.size > 0">
|
||||||
|
AND
|
||||||
|
file_id IN
|
||||||
|
<foreach collection="fileIds" index="index" open="(" separator="," close=")">
|
||||||
|
#{fileIds[${index}]}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
@ -0,0 +1,390 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<base th:href="${#request.getContextPath() + '/'} ">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="renderer" content="webkit">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||||
|
<link rel="stylesheet" href="assets/fonts/font-awesome/css/font-awesome.css"/>
|
||||||
|
<link rel="stylesheet" href="assets/layuiadmin/layui/css/layui.css" media="all">
|
||||||
|
<link rel="stylesheet" href="assets/layuiadmin/style/admin.css" media="all">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="layui-fluid layui-anim layui-anim-fadein">
|
||||||
|
<div class="layui-row">
|
||||||
|
<div class="layui-col-md12">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-body" id="cardBody">
|
||||||
|
<div class="test-table-reload-btn" style="margin-bottom: 10px;">
|
||||||
|
<div class="layui-inline">
|
||||||
|
<input type="text" id="keywords" class="layui-input search-item search-item-width-100" placeholder="输入关键字">
|
||||||
|
</div>
|
||||||
|
<div class="layui-inline">
|
||||||
|
<input type="text" id="startTime" class="layui-input search-item search-item-width-100" placeholder="开始时间" readonly>
|
||||||
|
</div>
|
||||||
|
<div class="layui-inline">
|
||||||
|
<input type="text" id="endTime" class="layui-input search-item search-item-width-100" placeholder="结束时间" readonly>
|
||||||
|
</div>
|
||||||
|
<button type="button" id="search" class="layui-btn layui-btn-sm">
|
||||||
|
<i class="fa fa-lg fa-search"></i> 搜索
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||||
|
<!-- 表头按钮组 -->
|
||||||
|
<script type="text/html" id="headerToolBar">
|
||||||
|
<div class="layui-btn-group">
|
||||||
|
<button type="button" class="layui-btn layui-btn-sm" lay-event="saveEvent">
|
||||||
|
<i class="fa fa-lg fa-plus"></i> 新增
|
||||||
|
</button>
|
||||||
|
<button type="button" class="layui-btn layui-btn-danger layui-btn-sm" lay-event="removeEvent">
|
||||||
|
<i class="fa fa-lg fa-trash"></i> 删除
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<span style="margin-left: 10px;"><i class="fa fa-warning"></i> 视频在线播放只支持MP4格式,格式不符点击"转码状态"列的"转码"按钮进行转码</span>
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="videoBoxBackGround" style="position: fixed;z-index: 1000;top: 0;left: 0;width: 100%;height: 100%;background-color: rgba(0,0,0,0.6); display: none;">
|
||||||
|
<div role="button" class="viewer-button viewer-close video-close-btn"></div>
|
||||||
|
<div id="videoBox" style="width: 600px; height: 400px; position: absolute; left: 50%; top: 50%; margin-left: -300px; margin-top: -200px;">
|
||||||
|
<div id="video" style="width: 100%; height: 100%"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="assets/js/vendor/ckplayer/ckplayer/ckplayer.js"></script>
|
||||||
|
<script src="assets/layuiadmin/layui/layui.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
layui.config({
|
||||||
|
base: 'assets/layuiadmin/'
|
||||||
|
}).extend({
|
||||||
|
index: 'lib/index'
|
||||||
|
}).use(['index', 'table', 'laydate', 'common'], function() {
|
||||||
|
var $ = layui.$;
|
||||||
|
var $win = $(window);
|
||||||
|
var table = layui.table;
|
||||||
|
var admin = layui.admin;
|
||||||
|
var laydate = layui.laydate;
|
||||||
|
var common = layui.common;
|
||||||
|
var resizeTimeout = null;
|
||||||
|
var tableUrl = 'api/file/media/video/listpage';
|
||||||
|
var ckPlayerFileId;
|
||||||
|
var ckPlayer = new ckplayer({
|
||||||
|
container: '#video',
|
||||||
|
variable: 'player',
|
||||||
|
flashplayer: false,
|
||||||
|
video: {
|
||||||
|
file: '',
|
||||||
|
type: 'video/mp4'
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化表格
|
||||||
|
function initTable() {
|
||||||
|
table.render({
|
||||||
|
elem: '#dataTable',
|
||||||
|
id: 'dataTable',
|
||||||
|
url: top.restAjax.path(tableUrl, []),
|
||||||
|
width: admin.screen() > 1 ? '100%' : '',
|
||||||
|
height: $win.height() - 90,
|
||||||
|
limit: 20,
|
||||||
|
limits: [20, 40, 60, 80, 100, 200],
|
||||||
|
toolbar: '#headerToolBar',
|
||||||
|
request: {
|
||||||
|
pageName: 'page',
|
||||||
|
limitName: 'rows'
|
||||||
|
},
|
||||||
|
cols: [
|
||||||
|
[
|
||||||
|
{type:'checkbox', fixed: 'left'},
|
||||||
|
{field:'rowNum', width:80, title: '序号', fixed: 'left', align:'center', templet: '<span>{{d.LAY_INDEX}}</span>'},
|
||||||
|
{field: 'fileId', width: 140, title: '文件ID', align:'center',
|
||||||
|
templet: function(row) {
|
||||||
|
var rowData = row[this.field];
|
||||||
|
if(typeof(rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
return rowData;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{field: 'fileName', width: 140, title: '文件名称', align:'center',
|
||||||
|
templet: function(row) {
|
||||||
|
var rowData = row[this.field];
|
||||||
|
if(typeof(rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
return '<a href="javascript:void(0);" lay-event="searchFileEvent"><i class="fa fa-video-camera"></i> '+ rowData +'</a>'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{field: 'fileType', width: 100, title: '文件类型', align:'center',
|
||||||
|
templet: function(row) {
|
||||||
|
var rowData = row[this.field];
|
||||||
|
if(typeof(rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
return rowData;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{field: 'fileSize', width: 120, title: '文件大小', align:'center',
|
||||||
|
templet: function(row) {
|
||||||
|
var rowData = row[this.field];
|
||||||
|
if(typeof(rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
return parseInt(rowData / 1000000) +'MB';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{field: 'widthHeight', width: 120, title: '分辨率', align:'center',
|
||||||
|
templet: function(row) {
|
||||||
|
return row.videoWidth +' ×️ '+ row.videoHeight;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{field: 'videoBitRate', width: 100, title: '比特率', align:'center',
|
||||||
|
templet: function(row) {
|
||||||
|
var rowData = row[this.field];
|
||||||
|
if(typeof(rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
return rowData;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{field: 'videoDuration', width: 100, title: '时长', align:'center',
|
||||||
|
templet: function(row) {
|
||||||
|
var rowData = row[this.field];
|
||||||
|
if(typeof(rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
var hour = parseInt(rowData / 3600000);
|
||||||
|
hour = hour < 10 ? '0'+ hour : hour;
|
||||||
|
var minute = parseInt(rowData % 3600000 / 60000);
|
||||||
|
minute = minute < 10 ? '0'+ minute : minute;
|
||||||
|
var second = parseInt(rowData % 3600000 % 60000 / 1000);
|
||||||
|
second = second < 10 ? '0'+ second : second;
|
||||||
|
return hour +':'+ minute +':'+ second;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{field: 'videoEncoder', width: 80, title: '编码', align:'center',
|
||||||
|
templet: function(row) {
|
||||||
|
var rowData = row[this.field];
|
||||||
|
if(typeof(rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
return rowData;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{field: 'videoFrameRate', width: 80, title: '帧率', align:'center',
|
||||||
|
templet: function(row) {
|
||||||
|
var rowData = row[this.field];
|
||||||
|
if(typeof(rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
return rowData;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{field: 'convertProgress', width: 100, title: '转换进度', align:'center', fixed: 'right',
|
||||||
|
templet: function(row) {
|
||||||
|
if(row.convertStatus === 'UN_CONVERTED') {
|
||||||
|
return '0%';
|
||||||
|
}
|
||||||
|
if(row.convertStatus === 'CONVERTED') {
|
||||||
|
return '100%';
|
||||||
|
}
|
||||||
|
return '<span id="progress_'+ row.fileId +'">0%</span>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{field: 'convertStatus', width: 100, title: '转码状态', align:'center', fixed: 'right',
|
||||||
|
templet: function(row) {
|
||||||
|
var rowData = row[this.field];
|
||||||
|
if(typeof(rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
if(rowData === 'UN_CONVERTED') {
|
||||||
|
return '<button type="button" class="layui-btn layui-btn-xs" lay-event="convertEvent">转码</button>';
|
||||||
|
}
|
||||||
|
if(rowData === 'CONVERTING') {
|
||||||
|
return '转码中';
|
||||||
|
}
|
||||||
|
if(rowData === 'CONVERTED') {
|
||||||
|
return '已转码';
|
||||||
|
}
|
||||||
|
return rowData;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
],
|
||||||
|
page: true,
|
||||||
|
parseData: function(data) {
|
||||||
|
return {
|
||||||
|
'code': 0,
|
||||||
|
'msg': '',
|
||||||
|
'count': data.total,
|
||||||
|
'data': data.rows
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 重载表格
|
||||||
|
function reloadTable(currentPage) {
|
||||||
|
table.reload('dataTable', {
|
||||||
|
url: top.restAjax.path(tableUrl, []),
|
||||||
|
where: {
|
||||||
|
keywords: $('#keywords').val(),
|
||||||
|
startTime: $('#startTime').val(),
|
||||||
|
endTime: $('#endTime').val()
|
||||||
|
},
|
||||||
|
page: {
|
||||||
|
curr: currentPage
|
||||||
|
},
|
||||||
|
height: $win.height() - 90,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 初始化日期
|
||||||
|
function initDate() {
|
||||||
|
// 日期选择
|
||||||
|
laydate.render({
|
||||||
|
elem: '#startTime',
|
||||||
|
format: 'yyyy-MM-dd'
|
||||||
|
});
|
||||||
|
laydate.render({
|
||||||
|
elem: '#endTime',
|
||||||
|
format: 'yyyy-MM-dd'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 删除
|
||||||
|
function removeFile(isRemoveSource, ids) {
|
||||||
|
var layIndex;
|
||||||
|
top.restAjax.delete(top.restAjax.path('api/file/media/video/remove/{isRemoveSource}/{ids}', [isRemoveSource, ids]), {}, null, function (code, data) {
|
||||||
|
top.dialog.msg(top.dataMessage.deleteSuccess, {time: 1000});
|
||||||
|
reloadTable();
|
||||||
|
}, function (code, data) {
|
||||||
|
top.dialog.msg(data.msg);
|
||||||
|
}, function () {
|
||||||
|
layIndex = top.dialog.msg(top.dataMessage.deleting, {icon: 16, time: 0, shade: 0.3});
|
||||||
|
}, function () {
|
||||||
|
top.dialog.close(layIndex);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function removeData(ids) {
|
||||||
|
top.dialog.msg(top.dataMessage.delete, {
|
||||||
|
time: 0,
|
||||||
|
btn: [top.dataMessage.button.yes, '同时删除文件(不可逆)', top.dataMessage.button.no],
|
||||||
|
shade: 0.3,
|
||||||
|
btn1: function (index) {
|
||||||
|
top.dialog.close(index);
|
||||||
|
removeFile(0, ids);
|
||||||
|
},
|
||||||
|
btn2: function(index) {
|
||||||
|
top.dialog.close(index);
|
||||||
|
removeFile(1, ids);
|
||||||
|
},
|
||||||
|
btn3: function(index) {
|
||||||
|
top.dialog.close(index);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function sseConvertProgress() {
|
||||||
|
var source = new EventSource(top.restAjax.path('api/file/media/video/get-convert-progress', []));
|
||||||
|
source.addEventListener('message', function(e) {
|
||||||
|
var data = JSON.parse(e.data);
|
||||||
|
$('#progress_'+ data.fileId).text(parseInt(data.percent) + '%');
|
||||||
|
if(data >= 100) {
|
||||||
|
setTimeout(function() {
|
||||||
|
reloadTable();
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
source.addEventListener('open', function(e) {}, false);
|
||||||
|
// 响应finish事件,主动关闭EventSource
|
||||||
|
source.addEventListener('finish', function(e) {
|
||||||
|
source.close();
|
||||||
|
}, false);
|
||||||
|
// 异常
|
||||||
|
source.addEventListener('error', function(e) {
|
||||||
|
if (e.readyState == EventSource.CLOSED) {
|
||||||
|
console.log("连接关闭");
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
initTable();
|
||||||
|
initDate();
|
||||||
|
sseConvertProgress();
|
||||||
|
|
||||||
|
// 事件 - 页面变化
|
||||||
|
$win.on('resize', function() {
|
||||||
|
clearTimeout(resizeTimeout);
|
||||||
|
resizeTimeout = setTimeout(function() {
|
||||||
|
reloadTable();
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
// 事件 - 搜索
|
||||||
|
$(document).on('click', '#search', function() {
|
||||||
|
reloadTable(1);
|
||||||
|
});
|
||||||
|
// 事件 - 增删改
|
||||||
|
table.on('toolbar(dataTable)', function(obj) {
|
||||||
|
var layEvent = obj.event;
|
||||||
|
var checkStatus = table.checkStatus('dataTable');
|
||||||
|
var checkDatas = checkStatus.data;
|
||||||
|
if(layEvent === 'saveEvent') {
|
||||||
|
top.dialog.open({
|
||||||
|
url: top.restAjax.path('route/file/media/video/upload', []),
|
||||||
|
title: '上传视频',
|
||||||
|
width: '500px',
|
||||||
|
height: '380px',
|
||||||
|
onClose: function() {
|
||||||
|
reloadTable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if(layEvent === 'removeEvent') {
|
||||||
|
if(checkDatas.length === 0) {
|
||||||
|
top.dialog.msg(top.dataMessage.table.selectDelete);
|
||||||
|
} else {
|
||||||
|
var ids = '';
|
||||||
|
for(var i = 0, item; item = checkDatas[i++];) {
|
||||||
|
if(i > 1) {
|
||||||
|
ids += '_';
|
||||||
|
}
|
||||||
|
ids += item['fileId'];
|
||||||
|
}
|
||||||
|
removeData(ids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
table.on('tool(dataTable)', function(obj) {
|
||||||
|
var data = obj.data;
|
||||||
|
var event = obj.event;
|
||||||
|
if(event === 'searchFileEvent') {
|
||||||
|
$('#videoBoxBackGround').show();
|
||||||
|
if(ckPlayerFileId == data.fileId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ckPlayer.newVideo({
|
||||||
|
video: 'route/file/media/video/download/true/'+ data.fileId
|
||||||
|
});
|
||||||
|
ckPlayerFileId = data.fileId;
|
||||||
|
} else if(event === 'convertEvent') {
|
||||||
|
top.dialog.confirm('转码成功后,源文件将删除,确定转码吗?', function(index) {
|
||||||
|
top.dialog.close(index);
|
||||||
|
top.restAjax.put(top.restAjax.path('api/file/media/video/convert/{fileId}', [data.fileId]), {}, null, function (code, data) {
|
||||||
|
top.dialog.msg('正在转码...');
|
||||||
|
reloadTable();
|
||||||
|
}, function (code, data) {
|
||||||
|
top.dialog.msg(data.msg);
|
||||||
|
}, function () {
|
||||||
|
layIndex = top.dialog.msg(top.dataMessage.deleting, {icon: 16, time: 0, shade: 0.3});
|
||||||
|
}, function () {
|
||||||
|
top.dialog.close(layIndex);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$('.video-close-btn').on('click', function() {
|
||||||
|
ckPlayer.videoPause();
|
||||||
|
$('#videoBoxBackGround').hide();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,75 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<base th:href="${#request.getContextPath() + '/'} ">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<link rel="stylesheet" type="text/css" href="assets/js/vendor/bootstrap/css/bootstrap.min.css"/>
|
||||||
|
<link rel="stylesheet" type="text/css" href="assets/js/vendor/bootstrap-fileupload/css/fileinput.min.css"/>
|
||||||
|
<style>
|
||||||
|
.krajee-default.file-preview-frame .kv-file-content {height: 150px !important;}
|
||||||
|
.krajee-default.file-preview-frame .file-thumbnail-footer {height: 70px !important;;}
|
||||||
|
.krajee-default .file-footer-caption {margin-bottom:30px !important;}
|
||||||
|
.krajee-default .file-thumb-progress .progress, .krajee-default .file-thumb-progress .progress-bar {height: 20px !important;}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="content" class="edit-content" style="padding: 5px;">
|
||||||
|
<div class="tile color">
|
||||||
|
<form id="form" method="post" class="form-horizontal" role="form" onsubmit="return doSubmitForm()">
|
||||||
|
<input id="uploadFile" th:name="video" type="file" multiple data-theme="fas" data-preview-file-type="text">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" id="types" th:value="${types}"/>
|
||||||
|
<input type="hidden" id="maxUploadCount" th:value="${maxUploadCount}"/>
|
||||||
|
<script type="text/javascript" src="assets/js/jquery-3.5.1.min.js"></script>
|
||||||
|
<script type="text/javascript" src="assets/js/vendor/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
<script type="text/javascript" src="assets/js/vendor/bootstrap-fileupload/js/fileinput.js"></script>
|
||||||
|
<script type="text/javascript" src="assets/js/vendor/bootstrap-fileupload/js/locales/zh.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var customType = top.restAjax.params(window.location.href).customType;
|
||||||
|
var uploadFileArray = [];
|
||||||
|
function closeBox() {
|
||||||
|
top.dialog.closeBox();
|
||||||
|
}
|
||||||
|
function doSubmitForm() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
$('#uploadFile').fileinput({
|
||||||
|
language: 'zh', // 中文
|
||||||
|
uploadUrl: top.restAjax.path('api/file/media/video/upload', []),
|
||||||
|
allowedFileExtensions: customType ? customType.split(',') : $('#types').val().split(','), // 文件后缀
|
||||||
|
showUpload: false, // 显示上传按钮
|
||||||
|
showRemove: false, // 显示删除按钮
|
||||||
|
showPreview: true, // 是否预览
|
||||||
|
showCaption: false, // 是否标题
|
||||||
|
showClose: false, // 右上角关闭
|
||||||
|
showCancel: true, // 取消上传
|
||||||
|
dropZoneEnabled: true, // 是否拖拽区域
|
||||||
|
minFileCount: 0,
|
||||||
|
maxFileCount: $('#maxUploadCount').val(), // 表示允许同时上传的最大文件个数
|
||||||
|
enctype: 'multipart/form-data',
|
||||||
|
previewFileType: 'any' // 预览文件格式
|
||||||
|
}).on('fileuploaded', function (event, data, previewId, index) {
|
||||||
|
var id = data.response;
|
||||||
|
uploadFileArray.push(id);
|
||||||
|
top.dialog.dialogData.uploadFileArray = uploadFileArray;
|
||||||
|
if(uploadFileArray.length >= maxFileCount) {
|
||||||
|
$('.btn-file').hide();
|
||||||
|
}
|
||||||
|
}).on('filesuccessremove', function(event, previewId, index) {
|
||||||
|
uploadFileArray.splice(index, 1);
|
||||||
|
if(uploadFileArray.length < maxFileCount) {
|
||||||
|
$('.btn-file').show();
|
||||||
|
}
|
||||||
|
top.dialog.dialogData.uploadFileArray = uploadFileArray;
|
||||||
|
}).on('fileerror', function(event, data, msg) {
|
||||||
|
top.dialog.msg(data.response.msg);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user