Commit 23b676e48384b66fdd88c77d3b894e0924d0a65d

Authored by 648540858
1 parent 1cce3324

添加对旧录像文件的处理

Showing 29 changed files with 580 additions and 2785 deletions
libs/jdbc-aarch/kingbase8-8.6.0.jar 0 → 100644
No preview for this file type
libs/jdbc-aarch/kingbase8-8.6.0.jre7.jar 0 → 100644
No preview for this file type
libs/jdbc-aarch/postgresql-42.2.9.jar 0 → 100644
No preview for this file type
libs/jdbc-aarch/postgresql-42.2.9.jre7.jar 0 → 100644
No preview for this file type
@@ -44,6 +44,49 @@ @@ -44,6 +44,49 @@
44 </dependency> 44 </dependency>
45 45
46 <dependency> 46 <dependency>
  47 + <groupId>org.springframework.boot</groupId>
  48 + <artifactId>spring-boot-starter-jdbc</artifactId>
  49 + </dependency>
  50 +
  51 + <!-- mysql数据库 -->
  52 + <dependency>
  53 + <groupId>mysql</groupId>
  54 + <artifactId>mysql-connector-java</artifactId>
  55 + <version>8.0.30</version>
  56 + </dependency>
  57 +
  58 + <!--postgresql-->
  59 + <dependency>
  60 + <groupId>org.postgresql</groupId>
  61 + <artifactId>postgresql</artifactId>
  62 + <version>42.5.1</version>
  63 + </dependency>
  64 +
  65 + <!-- kingbase人大金仓 -->
  66 + <!-- 手动下载驱动后安装 -->
  67 + <!-- mvn install:install-file -Dfile=/home/lin/soft/kingbase/jdbc-aarch/kingbase8-8.6.0.jar -DgroupId=com.kingbase -DartifactId=kingbase8 -Dversion=8.6.0 -Dpackaging=jar
  68 + -->
  69 + <dependency>
  70 + <groupId>com.kingbase</groupId>
  71 + <artifactId>kingbase8</artifactId>
  72 + <version>8.6.0</version>
  73 + <scope>system</scope>
  74 + <systemPath>${basedir}/libs/jdbc-aarch/kingbase8-8.6.0.jar</systemPath>
  75 + </dependency>
  76 +
  77 + <dependency>
  78 + <groupId>org.mybatis.spring.boot</groupId>
  79 + <artifactId>mybatis-spring-boot-starter</artifactId>
  80 + <version>2.2.2</version>
  81 + <exclusions>
  82 + <exclusion>
  83 + <groupId>com.zaxxer</groupId>
  84 + <artifactId>HikariCP</artifactId>
  85 + </exclusion>
  86 + </exclusions>
  87 + </dependency>
  88 +
  89 + <dependency>
47 <groupId>net.bramp.ffmpeg</groupId> 90 <groupId>net.bramp.ffmpeg</groupId>
48 <artifactId>ffmpeg</artifactId> 91 <artifactId>ffmpeg</artifactId>
49 <version>0.6.2</version> 92 <version>0.6.2</version>
@@ -56,18 +99,6 @@ @@ -56,18 +99,6 @@
56 <version>1.2.73</version> 99 <version>1.2.73</version>
57 </dependency> 100 </dependency>
58 101
59 - <!--在线文档 -->  
60 - <dependency>  
61 - <groupId>org.springdoc</groupId>  
62 - <artifactId>springdoc-openapi-ui</artifactId>  
63 - <version>1.6.10</version>  
64 - </dependency>  
65 - <dependency>  
66 - <groupId>com.github.xiaoymin</groupId>  
67 - <artifactId>knife4j-springdoc-ui</artifactId>  
68 - <version>3.0.3</version>  
69 - </dependency>  
70 -  
71 <dependency> 102 <dependency>
72 <groupId>org.mp4parser</groupId> 103 <groupId>org.mp4parser</groupId>
73 <artifactId>muxer</artifactId> 104 <artifactId>muxer</artifactId>
src/main/java/top/panll/assist/config/FastJsonRedisSerializer.java deleted 100755 → 0
1 -package top.panll.assist.config;  
2 -  
3 -import com.alibaba.fastjson.JSON;  
4 -import com.alibaba.fastjson.parser.ParserConfig;  
5 -import com.alibaba.fastjson.serializer.SerializerFeature;  
6 -import org.springframework.data.redis.serializer.RedisSerializer;  
7 -import org.springframework.data.redis.serializer.SerializationException;  
8 -  
9 -import java.nio.charset.Charset;  
10 -  
11 -public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {  
12 - private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");  
13 - private Class<T> clazz;  
14 -  
15 - /**  
16 - * 添加autotype白名单  
17 - * 解决redis反序列化对象时报错 :com.alibaba.fastjson.JSONException: autoType is not support  
18 - */  
19 - static {  
20 - ParserConfig.getGlobalInstance().addAccept("top.panll.assist");  
21 - }  
22 -  
23 - public FastJsonRedisSerializer(Class<T> clazz) {  
24 - super();  
25 - this.clazz = clazz;  
26 - }  
27 -  
28 - @Override  
29 - public byte[] serialize(T t) throws SerializationException {  
30 - if (null == t) {  
31 - return new byte[0];  
32 - }  
33 - return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);  
34 - }  
35 -  
36 - @Override  
37 - public T deserialize(byte[] bytes) throws SerializationException {  
38 - if (null == bytes || bytes.length <= 0) {  
39 - return null;  
40 - }  
41 - String str = new String(bytes, DEFAULT_CHARSET);  
42 - return JSON.parseObject(str, clazz);  
43 - }  
44 -}  
src/main/java/top/panll/assist/config/GlobalExceptionHandler.java deleted 100755 → 0
1 -package top.panll.assist.config;  
2 -  
3 -import org.slf4j.Logger;  
4 -import org.slf4j.LoggerFactory;  
5 -import org.springframework.http.HttpStatus;  
6 -import org.springframework.web.bind.annotation.ExceptionHandler;  
7 -import org.springframework.web.bind.annotation.ResponseStatus;  
8 -import org.springframework.web.bind.annotation.RestControllerAdvice;  
9 -import top.panll.assist.controller.bean.ControllerException;  
10 -import top.panll.assist.controller.bean.ErrorCode;  
11 -import top.panll.assist.controller.bean.WVPResult;  
12 -  
13 -/**  
14 - * 全局异常处理  
15 - */  
16 -@RestControllerAdvice  
17 -public class GlobalExceptionHandler {  
18 -  
19 - private final static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);  
20 -  
21 - /**  
22 - * 默认异常处理  
23 - * @param e 异常  
24 - * @return 统一返回结果  
25 - */  
26 - @ExceptionHandler(Exception.class)  
27 - @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)  
28 - public WVPResult<String> exceptionHandler(Exception e) {  
29 - logger.error("[全局异常]: ", e);  
30 - return WVPResult.fail(ErrorCode.ERROR500.getCode(), e.getMessage());  
31 - }  
32 -  
33 - /**  
34 - * 自定义异常处理, 处理controller中返回的错误  
35 - * @param e 异常  
36 - * @return 统一返回结果  
37 - */  
38 - @ExceptionHandler(ControllerException.class)  
39 - @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)  
40 - public WVPResult<String> exceptionHandler(ControllerException e) {  
41 - return WVPResult.fail(e.getCode(), e.getMsg());  
42 - }  
43 -  
44 -}  
src/main/java/top/panll/assist/config/GlobalResponseAdvice.java deleted 100755 → 0
1 -package top.panll.assist.config;  
2 -  
3 -import com.alibaba.fastjson.JSON;  
4 -import org.springframework.core.MethodParameter;  
5 -import org.springframework.http.MediaType;  
6 -import org.springframework.http.converter.HttpMessageConverter;  
7 -import org.springframework.http.server.ServerHttpRequest;  
8 -import org.springframework.http.server.ServerHttpResponse;  
9 -import org.springframework.web.bind.annotation.RestControllerAdvice;  
10 -import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;  
11 -import top.panll.assist.controller.bean.ErrorCode;  
12 -import top.panll.assist.controller.bean.WVPResult;  
13 -  
14 -import javax.validation.constraints.NotNull;  
15 -  
16 -/**  
17 - * 全局统一返回结果  
18 - * @author lin  
19 - */  
20 -@RestControllerAdvice  
21 -public class GlobalResponseAdvice implements ResponseBodyAdvice<Object> {  
22 -  
23 -  
24 - @Override  
25 - public boolean supports(@NotNull MethodParameter returnType, @NotNull Class<? extends HttpMessageConverter<?>> converterType) {  
26 - return true;  
27 - }  
28 -  
29 - @Override  
30 - public Object beforeBodyWrite(Object body, @NotNull MethodParameter returnType, @NotNull MediaType selectedContentType, @NotNull Class<? extends HttpMessageConverter<?>> selectedConverterType, @NotNull ServerHttpRequest request, @NotNull ServerHttpResponse response) {  
31 - // 排除api文档的接口,这个接口不需要统一  
32 - String[] excludePath = {"/v3/api-docs","/api/v1","/index/hook"};  
33 - for (String path : excludePath) {  
34 - if (request.getURI().getPath().startsWith(path)) {  
35 - return body;  
36 - }  
37 - }  
38 -  
39 - if (body instanceof WVPResult) {  
40 - return body;  
41 - }  
42 -  
43 - if (body instanceof ErrorCode) {  
44 - ErrorCode errorCode = (ErrorCode) body;  
45 - return new WVPResult<>(errorCode.getCode(), errorCode.getMsg(), null);  
46 - }  
47 -  
48 - if (body instanceof String) {  
49 - return JSON.toJSONString(WVPResult.success(body));  
50 - }  
51 -  
52 - return WVPResult.success(body);  
53 - }  
54 -}  
src/main/java/top/panll/assist/config/RedisConfig.java deleted 100755 → 0
1 -package top.panll.assist.config;  
2 -  
3 -import com.alibaba.fastjson.parser.ParserConfig;  
4 -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;  
5 -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;  
6 -import org.springframework.boot.autoconfigure.data.redis.RedisProperties;  
7 -import org.springframework.boot.context.properties.EnableConfigurationProperties;  
8 -import org.springframework.context.annotation.Bean;  
9 -import org.springframework.context.annotation.Configuration;  
10 -import org.springframework.data.redis.connection.RedisConnectionFactory;  
11 -import org.springframework.data.redis.core.RedisOperations;  
12 -import org.springframework.data.redis.core.RedisTemplate;  
13 -import org.springframework.data.redis.listener.RedisMessageListenerContainer;  
14 -import org.springframework.data.redis.serializer.StringRedisSerializer;  
15 -  
16 -/**  
17 - * @Description:Redis中间件配置类,使用spring-data-redis集成,自动从application.yml中加载redis配置  
18 - * @author: swwheihei  
19 - * @date: 2019年5月30日 上午10:58:25  
20 - *  
21 - */  
22 -@Configuration  
23 -@ConditionalOnClass(RedisOperations.class)  
24 -@EnableConfigurationProperties(RedisProperties.class)  
25 -public class RedisConfig {  
26 -  
27 - static {  
28 - ParserConfig.getGlobalInstance().addAccept("top.panll.assist");  
29 - }  
30 -  
31 - @Bean  
32 - @ConditionalOnMissingBean(name = "redisTemplate")  
33 - public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {  
34 - RedisTemplate<Object, Object> template = new RedisTemplate<>();  
35 - template.setConnectionFactory(redisConnectionFactory);  
36 - // 使用fastjson进行序列化处理,提高解析效率  
37 - FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<>(Object.class);  
38 - // value值的序列化采用fastJsonRedisSerializer  
39 - template.setValueSerializer(serializer);  
40 - template.setHashValueSerializer(serializer);  
41 - // key的序列化采用StringRedisSerializer  
42 - template.setKeySerializer(new StringRedisSerializer());  
43 - template.setHashKeySerializer(new StringRedisSerializer());  
44 - template.setConnectionFactory(redisConnectionFactory);  
45 - // 使用fastjson时需设置此项,否则会报异常not support type  
46 -// ParserConfig.getGlobalInstance().setAutoTypeSupport(true);  
47 - return template;  
48 -  
49 - }  
50 -  
51 - /**  
52 - * redis消息监听器容器 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器  
53 - * 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理  
54 - *  
55 - * @param connectionFactory  
56 - * @return  
57 - */  
58 - @Bean  
59 - RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {  
60 -  
61 - RedisMessageListenerContainer container = new RedisMessageListenerContainer();  
62 - container.setConnectionFactory(connectionFactory);  
63 - return container;  
64 - }  
65 -  
66 -}  
src/main/java/top/panll/assist/config/SpringDocConfig.java deleted 100755 → 0
1 -package top.panll.assist.config;  
2 -  
3 -import io.swagger.v3.oas.models.OpenAPI;  
4 -import io.swagger.v3.oas.models.info.Contact;  
5 -import io.swagger.v3.oas.models.info.Info;  
6 -import io.swagger.v3.oas.models.info.License;  
7 -import org.springdoc.core.GroupedOpenApi;  
8 -import org.springframework.beans.factory.annotation.Value;  
9 -import org.springframework.context.annotation.Bean;  
10 -import org.springframework.context.annotation.Configuration;  
11 -  
12 -/**  
13 - * @author lin  
14 - */  
15 -@Configuration  
16 -public class SpringDocConfig {  
17 -  
18 - @Value("${doc.enabled: true}")  
19 - private boolean enable;  
20 -  
21 - @Bean  
22 - public OpenAPI springShopOpenApi() {  
23 - Contact contact = new Contact();  
24 - contact.setName("pan");  
25 - contact.setEmail("648540858@qq.com");  
26 - return new OpenAPI()  
27 - .info(new Info().title("WVP-PRO-ASSIST 接口文档")  
28 - .contact(contact)  
29 - .description("WVP-PRO助手,补充ZLM功能")  
30 - .version("v2.0")  
31 - .license(new License().name("Apache 2.0").url("http://springdoc.org")));  
32 - }  
33 -  
34 - /**  
35 - * 添加分组  
36 - * @return  
37 - */  
38 - @Bean  
39 - public GroupedOpenApi publicApi() {  
40 - return GroupedOpenApi.builder()  
41 - .group("1. 全部")  
42 - .packagesToScan("top.panll.assist")  
43 - .build();  
44 - }  
45 -}  
src/main/java/top/panll/assist/config/StartConfig.java
1 package top.panll.assist.config; 1 package top.panll.assist.config;
2 2
3 -import net.bramp.ffmpeg.FFmpeg;  
4 -import net.bramp.ffmpeg.FFprobe;  
5 import org.slf4j.Logger; 3 import org.slf4j.Logger;
6 import org.slf4j.LoggerFactory; 4 import org.slf4j.LoggerFactory;
7 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.beans.factory.annotation.Autowired;
8 import org.springframework.beans.factory.annotation.Value; 6 import org.springframework.beans.factory.annotation.Value;
9 import org.springframework.boot.CommandLineRunner; 7 import org.springframework.boot.CommandLineRunner;
10 import org.springframework.core.annotation.Order; 8 import org.springframework.core.annotation.Order;
  9 +import org.springframework.jdbc.datasource.DataSourceTransactionManager;
11 import org.springframework.stereotype.Component; 10 import org.springframework.stereotype.Component;
12 -import top.panll.assist.dto.UserSettings;  
13 -import top.panll.assist.service.FFmpegExecUtils;  
14 -import top.panll.assist.service.VideoFileService; 11 +import org.springframework.transaction.TransactionDefinition;
  12 +import org.springframework.transaction.TransactionStatus;
  13 +import top.panll.assist.dto.CloudRecordItem;
  14 +import top.panll.assist.mapper.CloudRecordServiceMapper;
  15 +import top.panll.assist.utils.DateUtils;
15 16
16 import java.io.*; 17 import java.io.*;
17 -import java.nio.charset.StandardCharsets; 18 +import java.util.ArrayList;
  19 +import java.util.HashMap;
  20 +import java.util.List;
  21 +import java.util.Map;
18 22
19 /** 23 /**
20 * 用于启动检查环境 24 * 用于启动检查环境
21 */ 25 */
22 @Component 26 @Component
23 -@Order(value=1) 27 +@Order(value=10)
24 public class StartConfig implements CommandLineRunner { 28 public class StartConfig implements CommandLineRunner {
25 29
26 private final static Logger logger = LoggerFactory.getLogger(StartConfig.class); 30 private final static Logger logger = LoggerFactory.getLogger(StartConfig.class);
27 31
28 - @Value("${server.port}")  
29 - private String port; 32 + @Value("${user-settings.record}")
  33 + private String record;
  34 +
  35 + @Value("${user-settings.media-server-id}")
  36 + private String mediaServerId;
  37 +
  38 + @Autowired
  39 + DataSourceTransactionManager dataSourceTransactionManager;
30 40
31 @Autowired 41 @Autowired
32 - private UserSettings userSettings; 42 + TransactionDefinition transactionDefinition;
33 43
34 @Autowired 44 @Autowired
35 - private VideoFileService videoFileService; 45 + private CloudRecordServiceMapper cloudRecordServiceMapper;
36 46
37 47
38 @Override 48 @Override
39 public void run(String... args) { 49 public void run(String... args) {
40 - String record = userSettings.getRecord();  
41 if (!record.endsWith(File.separator)) { 50 if (!record.endsWith(File.separator)) {
42 - userSettings.setRecord(userSettings.getRecord() + File.separator); 51 + record = record + File.separator;
43 } 52 }
44 53
45 File recordFile = new File(record); 54 File recordFile = new File(record);
46 if (!recordFile.exists()){ 55 if (!recordFile.exists()){
47 - logger.warn("[userSettings.record]路径不存在,开始创建");  
48 - boolean mkResult = recordFile.mkdirs();  
49 - if (!mkResult) {  
50 - logger.info("[userSettings.record]目录创建失败");  
51 - System.exit(1);  
52 - }  
53 - }else {  
54 - if ( !recordFile.isDirectory()) {  
55 - logger.warn("[userSettings.record]路径是文件,请修改为目录");  
56 - System.exit(1);  
57 - }  
58 - if (!recordFile.canRead()) {  
59 - logger.error("[userSettings.record]路径无法读取");  
60 - System.exit(1); 56 + logger.warn("{}路径不存在", record);
  57 + System.exit(1);
  58 + }
  59 + logger.info("开始搜集数据");
  60 + File[] appFiles = recordFile.listFiles();
  61 + if (appFiles == null) {
  62 + logger.warn("{}路径下没有录像", record);
  63 + System.exit(1);
  64 + }
  65 + if (appFiles.length == 0) {
  66 + logger.warn("{}路径下没有录像", record);
  67 + System.exit(1);
  68 + }
  69 + List<CloudRecordItem> cloudRecordItemList = new ArrayList<>();
  70 + Map<String, String> renameMap = new HashMap<>();
  71 + // 搜集数据
  72 + for (File file : appFiles) {
  73 + if (!file.isDirectory()) {
  74 + continue;
61 } 75 }
62 - if (!recordFile.canWrite()) {  
63 - logger.error("[userSettings.record]路径无法写入");  
64 - System.exit(1); 76 + String app = file.getName();
  77 + File[] streamFiles = file.listFiles();
  78 + if (streamFiles == null || streamFiles.length == 0) {
  79 + continue;
65 } 80 }
66 - }  
67 -  
68 - try {  
69 -  
70 - // 对目录进行预整理  
71 - File[] appFiles = recordFile.listFiles();  
72 - if (appFiles != null && appFiles.length > 0) {  
73 - for (File appFile : appFiles) {  
74 - if (appFile.getName().equals("recordTemp")) {  
75 - continue;  
76 - }  
77 - File[] streamFiles = appFile.listFiles();  
78 - if (streamFiles != null && streamFiles.length > 0) {  
79 - for (File streamFile : streamFiles) {  
80 - File[] dateFiles = streamFile.listFiles();  
81 - if (dateFiles != null && dateFiles.length > 0) {  
82 - for (File dateFile : dateFiles) {  
83 - File[] files = dateFile.listFiles();  
84 - if (files != null && files.length > 0) {  
85 - for (File file : files) {  
86 - videoFileService.handFile(file, appFile.getName(), streamFile.getName());  
87 - } 81 + for (File streamFile : streamFiles) {
  82 + String stream = streamFile.getName();
  83 + if ("rtp".equals(app)) {
  84 +
  85 + }else {
  86 + if (stream.indexOf("_") > 0) {
  87 + String[] streamInfoArray = stream.split("_");
  88 + if (streamInfoArray.length != 2) {
  89 + logger.warn("无法识别 {}/{}", app, stream);
  90 + continue;
  91 + }
  92 + stream = streamInfoArray[0];
  93 + String callId = streamInfoArray[1];
  94 + File[] dateFiles = streamFile.listFiles();
  95 + if (dateFiles == null || dateFiles.length == 0) {
  96 + continue;
  97 + }
  98 + // TODC 确定关联和归档分别使用了什么类型名称
  99 + boolean collect = false;
  100 + boolean reserve = false;
  101 + for (File dateFile : dateFiles) {
  102 + if (dateFile.isFile()) {
  103 + if (dateFile.getName().endsWith(".sign")) {
  104 + if (dateFile.getName().startsWith("a")) {
  105 + collect = true;
  106 + }else if (dateFile.getName().startsWith("b")) {
  107 + reserve = true;
88 } 108 }
89 } 109 }
  110 + }else {
  111 + // 检验是否是日期格式
  112 + if (!DateUtils.checkDateFormat(dateFile.getName())) {
  113 + continue;
  114 + }
  115 + String date = dateFile.getName();
  116 + File[] videoFiles = dateFile.listFiles();
  117 + if (videoFiles == null || videoFiles.length == 0) {
  118 + continue;
  119 + }
  120 + for (int i = 0; i < videoFiles.length; i++) {
  121 + File videoFile = videoFiles[i];
  122 + if (!videoFile.getName().endsWith(".mp4") && !videoFile.getName().contains("-")) {
  123 + continue;
  124 + }
  125 + String[] videoInfoArray = videoFile.getName().split("-");
  126 + if (videoInfoArray.length != 3) {
  127 + logger.info("非目标视频文件格式,忽略此文件: {}", videoFile.getAbsolutePath() );
  128 + continue;
  129 + }
  130 + if (!DateUtils.checkDateTimeFormat(date + " " + videoInfoArray[0])
  131 + || !DateUtils.checkDateTimeFormat(date + " " + videoInfoArray[1]) ) {
  132 + logger.info("目标视频文件明明异常,忽略此文件: {}", videoFile.getName() );
  133 + continue;
  134 + }
  135 + String startTime = date + " " + videoInfoArray[0];
  136 + String endTime = date + " " + videoInfoArray[1];
  137 + Long startTimeStamp = DateUtils.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime);
  138 + Long endTimeStamp = DateUtils.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime);
  139 +
  140 + long timeLength = Long.parseLong(videoInfoArray[2].substring(0, videoInfoArray[2].length() - 4));
  141 + CloudRecordItem cloudRecordItem = new CloudRecordItem();
  142 + cloudRecordItem.setApp(app);
  143 + cloudRecordItem.setStream(stream);
  144 + cloudRecordItem.setCallId(callId);
  145 + cloudRecordItem.setStartTime(startTimeStamp);
  146 + cloudRecordItem.setEndTime(endTimeStamp);
  147 + cloudRecordItem.setCollect(collect);
  148 + cloudRecordItem.setReserve(reserve);
  149 + cloudRecordItem.setMediaServerId(mediaServerId);
  150 + cloudRecordItem.setFileName(DateUtils.getTimeStr(startTimeStamp) + "-" + i + ".mp4");
  151 + cloudRecordItem.setFolder(streamFile.getAbsolutePath());
  152 + cloudRecordItem.setFileSize(videoFile.length());
  153 + cloudRecordItem.setTimeLen(timeLength);
  154 + cloudRecordItem.setFilePath(videoFile.getParentFile().getAbsolutePath() + File.separator + cloudRecordItem.getFileName());
  155 + cloudRecordItemList.add(cloudRecordItem);
  156 + renameMap.put(videoFile.getAbsolutePath(), cloudRecordItem.getFilePath());
  157 + System.out.println(cloudRecordItem.getFilePath());
  158 + }
90 } 159 }
91 -  
92 } 160 }
93 } 161 }
94 -  
95 } 162 }
96 } 163 }
97 -  
98 - } catch (Exception exception){  
99 - exception.printStackTrace();  
100 - logger.error("环境错误: " + exception.getMessage()); 164 + logger.info("数据收集完成, 待处理数据为: {}条", cloudRecordItemList.size());
  165 + logger.info("开始将数据写入数据库");
  166 + TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
  167 + int limitCount = 50;
  168 + if (cloudRecordItemList.size() > 0) {
  169 + if (cloudRecordItemList.size() > limitCount) {
  170 + for (int i = 0; i < cloudRecordItemList.size(); i += limitCount) {
  171 + int toIndex = i + limitCount;
  172 + if (i + limitCount > cloudRecordItemList.size()) {
  173 + toIndex = cloudRecordItemList.size();
  174 + }
  175 + int length = cloudRecordServiceMapper.batchAdd(cloudRecordItemList.subList(i, toIndex));
  176 + if (length == 0) {
  177 + dataSourceTransactionManager.rollback(transactionStatus);
  178 + }
  179 + }
  180 + } else {
  181 + cloudRecordServiceMapper.batchAdd(cloudRecordItemList);
  182 + }
  183 + dataSourceTransactionManager.commit(transactionStatus);
  184 + }
  185 + logger.info("数据写入数据库完成");
101 } 186 }
  187 +
  188 +
102 } 189 }
103 190
104 -// private void writeAssistDownPage(File recordFile) {  
105 -// try {  
106 -// File file = new File(recordFile.getParentFile().getAbsolutePath(), "download.html");  
107 -// if (file.exists()) {  
108 -// file.delete();  
109 -// }  
110 -// file.createNewFile();  
111 -// FileOutputStream fs = new FileOutputStream(file);  
112 -// StringBuffer stringBuffer = new StringBuffer();  
113 -// String content = "<!DOCTYPE html>\n" +  
114 -// "<html lang=\"en\">\n" +  
115 -// "<head>\n" +  
116 -// " <meta charset=\"UTF-8\">\n" +  
117 -// " <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n" +  
118 -// " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +  
119 -// " <title>下载</title>\n" +  
120 -// "</head>\n" +  
121 -// "<body>\n" +  
122 -// " <a id=\"download\" download />\n" +  
123 -// " <script>\n" +  
124 -// " (function(){\n" +  
125 -// " let searchParams = new URLSearchParams(location.search);\n" +  
126 -// " var download = document.getElementById(\"download\");\n" +  
127 -// " download.setAttribute(\"href\", searchParams.get(\"url\"))\n" +  
128 -// " download.click()\n" +  
129 -// " setTimeout(()=>{\n" +  
130 -// " window.location.href=\"about:blank\";\n" +  
131 -// "\t\t\t window.close();\n" +  
132 -// " },200)\n" +  
133 -// " })();\n" +  
134 -// " \n" +  
135 -// " </script>\n" +  
136 -// "</body>\n" +  
137 -// "</html>";  
138 -// fs.write(content.getBytes(StandardCharsets.UTF_8));  
139 -// logger.info("已写入html配置页面: " + file.getAbsolutePath());  
140 -// } catch (FileNotFoundException e) {  
141 -// logger.error("写入html页面错误", e);  
142 -// } catch (IOException e) {  
143 -// logger.error("写入html页面错误", e);  
144 -// }  
145 -//  
146 -//  
147 -// } 191 +
148 } 192 }
src/main/java/top/panll/assist/config/WebMvcConfig.java deleted 100755 → 0
1 -package top.panll.assist.config;  
2 -  
3 -import org.springframework.beans.factory.annotation.Autowired;  
4 -import org.springframework.context.annotation.Configuration;  
5 -import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;  
6 -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;  
7 -import top.panll.assist.dto.UserSettings;  
8 -  
9 -import java.io.File;  
10 -  
11 -  
12 -@Configuration  
13 -public class WebMvcConfig extends WebMvcConfigurerAdapter {  
14 -  
15 - @Autowired  
16 - private UserSettings userSettings;  
17 -  
18 - @Override  
19 - public void addResourceHandlers(ResourceHandlerRegistry registry) {  
20 - File file = new File(userSettings.getRecord());  
21 - registry.addResourceHandler("/download/**").addResourceLocations("file://" + file.getAbsolutePath() + "/");  
22 - super.addResourceHandlers(registry);  
23 - }  
24 -}  
src/main/java/top/panll/assist/controller/DownController.java deleted 100755 → 0
1 -package top.panll.assist.controller;  
2 -  
3 -  
4 -import org.apache.catalina.connector.ClientAbortException;  
5 -import org.mp4parser.BasicContainer;  
6 -import org.mp4parser.Container;  
7 -import org.mp4parser.muxer.Movie;  
8 -import org.mp4parser.muxer.Track;  
9 -import org.mp4parser.muxer.builder.DefaultMp4Builder;  
10 -import org.mp4parser.muxer.builder.Mp4Builder;  
11 -import org.mp4parser.muxer.container.mp4.MovieCreator;  
12 -import org.mp4parser.muxer.tracks.AppendTrack;  
13 -import org.slf4j.Logger;  
14 -import org.slf4j.LoggerFactory;  
15 -import org.springframework.beans.factory.annotation.Autowired;  
16 -import org.springframework.stereotype.Controller;  
17 -import org.springframework.web.bind.annotation.GetMapping;  
18 -import org.springframework.web.bind.annotation.RequestMapping;  
19 -import org.springframework.web.bind.annotation.ResponseBody;  
20 -import top.panll.assist.dto.UserSettings;  
21 -  
22 -import javax.servlet.http.HttpServletRequest;  
23 -import javax.servlet.http.HttpServletResponse;  
24 -import java.io.*;  
25 -import java.nio.channels.Channels;  
26 -import java.nio.channels.WritableByteChannel;  
27 -import java.nio.charset.StandardCharsets;  
28 -import java.util.ArrayList;  
29 -import java.util.LinkedList;  
30 -import java.util.List;  
31 -  
32 -@Controller  
33 -@RequestMapping("/down")  
34 -public class DownController {  
35 -  
36 - private final static Logger logger = LoggerFactory.getLogger(DownController.class);  
37 -  
38 - @Autowired  
39 - private UserSettings userSettings;  
40 -  
41 - /**  
42 - * 获取app+stream列表  
43 - *  
44 - * @return  
45 - */  
46 - @GetMapping(value = "/**")  
47 - @ResponseBody  
48 - public void download(HttpServletRequest request, HttpServletResponse response) throws IOException {  
49 -  
50 - List<String> videoList = new ArrayList<>();  
51 - videoList.add("/home/lin/server/test/zlm/Debug/www/record/rtp/34020000002000000003_34020000001310000001/2023-03-20/16-09-07.mp4");  
52 - videoList.add("/home/lin/server/test/zlm/Debug/www/record/rtp/34020000002000000003_34020000001310000001/2023-03-20/17-12-10.mp4");  
53 - videoList.add("/home/lin/server/test/zlm/Debug/www/record/rtp/34020000002000000003_34020000001310000001/2023-03-20/17-38-36.mp4");  
54 - List<Movie> sourceMovies = new ArrayList<>();  
55 - for (String video : videoList) {  
56 - sourceMovies.add(MovieCreator.build(video));  
57 - }  
58 -  
59 - List<Track> videoTracks = new LinkedList<>();  
60 - List<Track> audioTracks = new LinkedList<>();  
61 - for (Movie movie : sourceMovies) {  
62 - for (Track track : movie.getTracks()) {  
63 - if ("soun".equals(track.getHandler())) {  
64 - audioTracks.add(track);  
65 - }  
66 -  
67 - if ("vide".equals(track.getHandler())) {  
68 - videoTracks.add(track);  
69 - }  
70 - }  
71 - }  
72 - Movie mergeMovie = new Movie();  
73 - if (audioTracks.size() > 0) {  
74 - mergeMovie.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));  
75 - }  
76 -  
77 - if (videoTracks.size() > 0) {  
78 - mergeMovie.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));  
79 - }  
80 -  
81 - BasicContainer out = (BasicContainer)new DefaultMp4Builder().build(mergeMovie);  
82 -  
83 - // 文件名  
84 - String fileName = "测试.mp4";  
85 - // 文件类型  
86 - String contentType = request.getServletContext().getMimeType(fileName);  
87 -  
88 - // 解决下载文件时文件名乱码问题  
89 - byte[] fileNameBytes = fileName.getBytes(StandardCharsets.UTF_8);  
90 - fileName = new String(fileNameBytes, 0, fileNameBytes.length, StandardCharsets.ISO_8859_1);  
91 -  
92 - response.setHeader("Content-Type", contentType);  
93 - response.setHeader("Content-Length", String.valueOf(out));  
94 - //inline表示浏览器直接使用,attachment表示下载,fileName表示下载的文件名  
95 - response.setHeader("Content-Disposition", "inline;filename=" + fileName);  
96 - response.setContentType(contentType);  
97 -  
98 - WritableByteChannel writableByteChannel = Channels.newChannel(response.getOutputStream());  
99 - out.writeContainer(writableByteChannel);  
100 - writableByteChannel.close();  
101 -  
102 - }  
103 -}  
src/main/java/top/panll/assist/controller/RecordController.java deleted 100755 → 0
1 -package top.panll.assist.controller;  
2 -  
3 -import com.alibaba.fastjson.JSON;  
4 -import com.alibaba.fastjson.JSONObject;  
5 -import io.swagger.v3.oas.annotations.Operation;  
6 -import io.swagger.v3.oas.annotations.Parameter;  
7 -import io.swagger.v3.oas.annotations.tags.Tag;  
8 -import org.apache.commons.io.FileUtils;  
9 -import org.slf4j.Logger;  
10 -import org.slf4j.LoggerFactory;  
11 -import org.springframework.beans.factory.annotation.Autowired;  
12 -import org.springframework.http.HttpStatus;  
13 -import org.springframework.http.ResponseEntity;  
14 -import org.springframework.web.bind.annotation.*;  
15 -import top.panll.assist.controller.bean.ControllerException;  
16 -import top.panll.assist.controller.bean.ErrorCode;  
17 -import top.panll.assist.controller.bean.RecordFile;  
18 -import top.panll.assist.controller.bean.WVPResult;  
19 -import top.panll.assist.dto.*;  
20 -import top.panll.assist.service.VideoFileService;  
21 -import top.panll.assist.utils.PageInfo;  
22 -import top.panll.assist.utils.RedisUtil;  
23 -  
24 -import javax.servlet.http.HttpServletRequest;  
25 -import java.io.File;  
26 -import java.text.DateFormat;  
27 -import java.text.ParseException;  
28 -import java.text.SimpleDateFormat;  
29 -import java.util.*;  
30 -  
31 -@Tag(name = "录像管理", description = "录像管理")  
32 -@CrossOrigin  
33 -@RestController  
34 -@RequestMapping("/api/record")  
35 -public class RecordController {  
36 -  
37 - private final static Logger logger = LoggerFactory.getLogger(RecordController.class);  
38 -  
39 - @Autowired  
40 - private VideoFileService videoFileService;  
41 -  
42 - @Autowired  
43 - private RedisUtil redisUtil;  
44 -  
45 - @Autowired  
46 - private UserSettings userSettings;  
47 -  
48 - private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
49 -  
50 -  
51 - /**  
52 - * 获取Assist服务配置信息  
53 - */  
54 - @Operation(summary ="获取Assist服务配置信息")  
55 - @GetMapping(value = "/info")  
56 - @ResponseBody  
57 - public UserSettings getInfo(){  
58 - return userSettings;  
59 - }  
60 -  
61 - /**  
62 - * 获取app+stream列表  
63 - * @return  
64 - */  
65 - @Operation(summary ="分页获取app+stream的列表")  
66 - @Parameter(name = "page", description = "当前页", required = true)  
67 - @Parameter(name = "count", description = "每页查询数量", required = true)  
68 - @GetMapping(value = "/list")  
69 - @ResponseBody  
70 - public PageInfo<Map<String, String>> getList(@RequestParam int page,  
71 - @RequestParam int count){  
72 - List<Map<String, String>> appList = videoFileService.getList();  
73 -  
74 - PageInfo<Map<String, String>> stringPageInfo = new PageInfo<>(appList);  
75 - stringPageInfo.startPage(page, count);  
76 - return stringPageInfo;  
77 - }  
78 -  
79 - /**  
80 - * 分页获取app列表  
81 - * @return  
82 - */  
83 - @Operation(summary ="分页获取app列表")  
84 - @Parameter(name = "page", description = "当前页", required = true)  
85 - @Parameter(name = "count", description = "每页查询数量", required = true)  
86 - @GetMapping(value = "/app/list")  
87 - @ResponseBody  
88 - public PageInfo<String> getAppList(@RequestParam int page,  
89 - @RequestParam int count){  
90 - List<String> resultData = new ArrayList<>();  
91 - List<File> appList = videoFileService.getAppList(true);  
92 - if (appList.size() > 0) {  
93 - for (File file : appList) {  
94 - resultData.add(file.getName());  
95 - }  
96 - }  
97 - Collections.sort(resultData);  
98 -  
99 - PageInfo<String> stringPageInfo = new PageInfo<>(resultData);  
100 - stringPageInfo.startPage(page, count);  
101 - return stringPageInfo;  
102 - }  
103 -  
104 - /**  
105 - * 分页stream列表  
106 - * @return  
107 - */  
108 - @Operation(summary ="分页stream列表")  
109 - @Parameter(name = "page", description = "当前页", required = true)  
110 - @Parameter(name = "count", description = "每页查询数量", required = true)  
111 - @Parameter(name = "app", description = "应用名", required = true)  
112 - @GetMapping(value = "/stream/list")  
113 - @ResponseBody  
114 - public PageInfo<String> getStreamList(@RequestParam int page,  
115 - @RequestParam int count,  
116 - @RequestParam String app ){  
117 - List<String> resultData = new ArrayList<>();  
118 - if (app == null) {  
119 - throw new ControllerException(ErrorCode.ERROR400.getCode(), "app不能为空");  
120 - }  
121 - List<File> streamList = videoFileService.getStreamList(app, true);  
122 - if (streamList != null) {  
123 - for (File file : streamList) {  
124 - resultData.add(file.getName());  
125 - }  
126 - }  
127 - PageInfo<String> stringPageInfo = new PageInfo<>(resultData);  
128 - stringPageInfo.startPage(page, count);  
129 - return stringPageInfo;  
130 - }  
131 -  
132 - /**  
133 - * 获取日期文件夹列表  
134 - * @return  
135 - */  
136 - @Operation(summary ="获取日期文件夹列表")  
137 - @Parameter(name = "year", description = "月", required = true)  
138 - @Parameter(name = "month", description = "年", required = true)  
139 - @Parameter(name = "app", description = "应用名", required = true)  
140 - @Parameter(name = "stream", description = "流ID", required = true)  
141 - @GetMapping(value = "/date/list")  
142 - @ResponseBody  
143 - public List<String> getDateList( @RequestParam(required = false) Integer year,  
144 - @RequestParam(required = false) Integer month,  
145 - @RequestParam String app,  
146 - @RequestParam String stream ){  
147 - List<String> resultData = new ArrayList<>();  
148 - if (app == null) {  
149 - throw new ControllerException(ErrorCode.ERROR400.getCode(), "app不能为空");  
150 - };  
151 - if (stream == null) {  
152 - throw new ControllerException(ErrorCode.ERROR400.getCode(), "stream不能为空");  
153 - }  
154 - List<File> dateList = videoFileService.getDateList(app, stream, year, month, true);  
155 - for (File file : dateList) {  
156 - resultData.add(file.getName());  
157 - }  
158 - return resultData;  
159 - }  
160 -  
161 - /**  
162 - * 获取视频文件列表  
163 - * @return  
164 - */  
165 - @Operation(summary ="获取视频文件列表")  
166 - @Parameter(name = "page", description = "当前页", required = true)  
167 - @Parameter(name = "count", description = "每页查询数量", required = true)  
168 - @Parameter(name = "app", description = "应用名", required = true)  
169 - @Parameter(name = "stream", description = "流ID", required = true)  
170 - @Parameter(name = "startTime", description = "开始时间(yyyy-MM-dd HH:mm:ss)", required = true)  
171 - @Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = true)  
172 - @GetMapping(value = "/file/list")  
173 - @ResponseBody  
174 - public PageInfo<String> getRecordList(@RequestParam int page,  
175 - @RequestParam int count,  
176 - @RequestParam String app,  
177 - @RequestParam String stream,  
178 - @RequestParam(required = false) String startTime,  
179 - @RequestParam(required = false) String endTime  
180 - ){  
181 -  
182 - // 开始时间与结束时间可不传或只传其一  
183 - List<String> recordList = new ArrayList<>();  
184 - try {  
185 - Date startTimeDate = null;  
186 - Date endTimeDate = null;  
187 - if (startTime != null ) {  
188 - startTimeDate = formatter.parse(startTime);  
189 - }  
190 - if (endTime != null ) {  
191 - endTimeDate = formatter.parse(endTime);  
192 - }  
193 -  
194 - List<File> filesInTime = videoFileService.getFilesInTime(app, stream, startTimeDate, endTimeDate);  
195 - if (filesInTime != null && filesInTime.size() > 0) {  
196 - for (File file : filesInTime) {  
197 - recordList.add(file.getName());  
198 - }  
199 - }  
200 - PageInfo<String> stringPageInfo = new PageInfo<>(recordList);  
201 - stringPageInfo.startPage(page, count);  
202 - return stringPageInfo;  
203 - } catch (ParseException e) {  
204 - logger.error("错误的开始时间[{}]或结束时间[{}]", startTime, endTime);  
205 - throw new ControllerException(ErrorCode.ERROR400.getCode(), "错误的开始时间或结束时间, e=" + e.getMessage());  
206 - }  
207 - }  
208 -  
209 - /**  
210 - * 获取视频文件列表  
211 - * @return  
212 - */  
213 - @Operation(summary ="获取视频文件列表")  
214 - @Parameter(name = "page", description = "当前页", required = true)  
215 - @Parameter(name = "count", description = "每页查询数量", required = true)  
216 - @Parameter(name = "app", description = "应用名", required = true)  
217 - @Parameter(name = "stream", description = "流ID", required = true)  
218 - @Parameter(name = "startTime", description = "开始时间(yyyy-MM-dd HH:mm:ss)", required = true)  
219 - @Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = true)  
220 - @GetMapping(value = "/file/listWithDate")  
221 - @ResponseBody  
222 - public PageInfo<RecordFile> getRecordListWithDate(@RequestParam int page,  
223 - @RequestParam int count,  
224 - @RequestParam String app,  
225 - @RequestParam String stream,  
226 - @RequestParam(required = false) String startTime,  
227 - @RequestParam(required = false) String endTime  
228 - ){  
229 -  
230 - // 开始时间与结束时间可不传或只传其一  
231 - List<RecordFile> recordList = new ArrayList<>();  
232 - try {  
233 - Date startTimeDate = null;  
234 - Date endTimeDate = null;  
235 - if (startTime != null ) {  
236 - startTimeDate = formatter.parse(startTime);  
237 - }  
238 - if (endTime != null ) {  
239 - endTimeDate = formatter.parse(endTime);  
240 - }  
241 -  
242 - List<File> filesInTime = videoFileService.getFilesInTime(app, stream, startTimeDate, endTimeDate);  
243 - if (filesInTime != null && filesInTime.size() > 0) {  
244 - for (File file : filesInTime) {  
245 - recordList.add(RecordFile.instance(app, stream, file.getName(), file.getParentFile().getName()));  
246 - }  
247 - }  
248 - PageInfo<RecordFile> stringPageInfo = new PageInfo<>(recordList);  
249 - stringPageInfo.startPage(page, count);  
250 - return stringPageInfo;  
251 - } catch (ParseException e) {  
252 - logger.error("错误的开始时间[{}]或结束时间[{}]", startTime, endTime);  
253 - throw new ControllerException(ErrorCode.ERROR400.getCode(), "错误的开始时间或结束时间, e=" + e.getMessage());  
254 - }  
255 - }  
256 -  
257 -  
258 - /**  
259 - * 添加视频裁剪合并任务  
260 - */  
261 - @Operation(summary ="添加视频裁剪合并任务")  
262 - @Parameter(name = "app", description = "应用名", required = true)  
263 - @Parameter(name = "stream", description = "流ID", required = true)  
264 - @Parameter(name = "startTime", description = "开始时间(yyyy-MM-dd HH:mm:ss)", required = true)  
265 - @Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = true)  
266 - @Parameter(name = "remoteHost", description = "服务的IP:端口(用于直接返回完整播放地址以及下载地址)", required = true)  
267 - @GetMapping(value = "/file/download/task/add")  
268 - @ResponseBody  
269 - public String addTaskForDownload(@RequestParam String app,  
270 - @RequestParam String stream,  
271 - @RequestParam(required = false) String startTime,  
272 - @RequestParam(required = false) String endTime,  
273 - @RequestParam(required = false) String remoteHost  
274 - ){  
275 - Date startTimeDate = null;  
276 - Date endTimeDate = null;  
277 - try {  
278 - if (startTime != null ) {  
279 - startTimeDate = formatter.parse(startTime);  
280 - }  
281 - if (endTime != null ) {  
282 - endTimeDate = formatter.parse(endTime);  
283 - }  
284 - } catch (ParseException e) {  
285 - e.printStackTrace();  
286 - }  
287 - String id = videoFileService.mergeOrCut(app, stream, startTimeDate, endTimeDate, remoteHost);  
288 - if (id== null) {  
289 - throw new ControllerException(ErrorCode.ERROR100.getCode(), "可能未找到视频文件");  
290 - }  
291 - return id;  
292 - }  
293 -  
294 - /**  
295 - * 查询视频裁剪合并任务列表  
296 - */  
297 - @Operation(summary ="查询视频裁剪合并任务列表")  
298 - @Parameter(name = "app", description = "应用名", required = true)  
299 - @Parameter(name = "stream", description = "流ID", required = true)  
300 - @Parameter(name = "taskId", description = "任务ID", required = true)  
301 - @Parameter(name = "isEnd", description = "是否结束", required = true)  
302 - @GetMapping(value = "/file/download/task/list")  
303 - @ResponseBody  
304 - public List<MergeOrCutTaskInfo> getTaskListForDownload(  
305 - @RequestParam(required = false) String app,  
306 - @RequestParam(required = false) String stream,  
307 - @RequestParam(required = false) String taskId,  
308 - @RequestParam(required = false) Boolean isEnd){  
309 - List<MergeOrCutTaskInfo> taskList = videoFileService.getTaskListForDownload(isEnd, app, stream, taskId);  
310 - if (taskList == null) {  
311 - throw new ControllerException(ErrorCode.ERROR100);  
312 - }  
313 - return taskList;  
314 - }  
315 -  
316 - /**  
317 - * 收藏录像(被收藏的录像不会被清理任务清理)  
318 - */  
319 - @Operation(summary ="收藏录像(被收藏的录像不会被清理任务清理)")  
320 - @Parameter(name = "type", description = "类型", required = true)  
321 - @Parameter(name = "app", description = "应用名", required = true)  
322 - @Parameter(name = "stream", description = "流ID", required = true)  
323 - @GetMapping(value = "/file/collection/add")  
324 - @ResponseBody  
325 - public void collection(  
326 - @RequestParam(required = true) String type,  
327 - @RequestParam(required = true) String app,  
328 - @RequestParam(required = true) String stream){  
329 -  
330 - boolean collectionResult = videoFileService.collection(app, stream, type);  
331 - if (!collectionResult) {  
332 - throw new ControllerException(ErrorCode.ERROR100);  
333 - }  
334 - }  
335 -  
336 - /**  
337 - * 移除收藏录像  
338 - */  
339 - @Operation(summary ="移除收藏录像")  
340 - @Parameter(name = "type", description = "类型", required = true)  
341 - @Parameter(name = "app", description = "应用名", required = true)  
342 - @Parameter(name = "stream", description = "流ID", required = true)  
343 - @GetMapping(value = "/file/collection/remove")  
344 - @ResponseBody  
345 - public void removeCollection(  
346 - @RequestParam(required = true) String type,  
347 - @RequestParam(required = true) String app,  
348 - @RequestParam(required = true) String stream){  
349 -  
350 - boolean collectionResult = videoFileService.removeCollection(app, stream, type);  
351 - if (!collectionResult) {  
352 - throw new ControllerException(ErrorCode.ERROR100);  
353 - }  
354 - }  
355 -  
356 - /**  
357 - * 收藏录像列表  
358 - */  
359 - @Operation(summary ="收藏录像列表")  
360 - @Parameter(name = "type", description = "类型", required = false)  
361 - @Parameter(name = "app", description = "应用名", required = false)  
362 - @Parameter(name = "stream", description = "流ID", required = false)  
363 - @GetMapping(value = "/file/collection/list")  
364 - @ResponseBody  
365 - public List<SignInfo> collectionList(  
366 - @RequestParam(required = false) String type,  
367 - @RequestParam(required = false) String app,  
368 - @RequestParam(required = false) String stream){  
369 -  
370 - List<SignInfo> signInfos = videoFileService.getCollectionList(app, stream, type);  
371 - return signInfos;  
372 - }  
373 -  
374 - /**  
375 - * 中止视频裁剪合并任务列表  
376 - */  
377 - @Operation(summary ="中止视频裁剪合并任务列表(暂不支持)")  
378 - @GetMapping(value = "/file/download/task/stop")  
379 - @ResponseBody  
380 - public WVPResult<String> stopTaskForDownload(@RequestParam String taskId){  
381 -// WVPResult<String> result = new WVPResult<>();  
382 -// if (taskId == null) {  
383 -// result.setCode(400);  
384 -// result.setMsg("taskId 不能为空");  
385 -// return result;  
386 -// }  
387 -// boolean stopResult = videoFileService.stopTask(taskId);  
388 -// result.setCode(0);  
389 -// result.setMsg(stopResult ? "success": "fail");  
390 - return null;  
391 - }  
392 -  
393 - /**  
394 - * 录制完成的通知, 对用zlm的hook  
395 - * @return  
396 - */  
397 - @ResponseBody  
398 - @PostMapping(value = "/on_record_mp4", produces = "application/json;charset=UTF-8")  
399 - public ResponseEntity<String> onRecordMp4(@RequestBody JSONObject json) {  
400 - JSONObject ret = new JSONObject();  
401 - ret.put("code", 0);  
402 - ret.put("msg", "success");  
403 - String file_path = json.getString("file_path");  
404 -  
405 - String app = json.getString("app");  
406 - String stream = json.getString("stream");  
407 - logger.debug("ZLM 录制完成,文件路径:" + file_path);  
408 -  
409 - if (file_path == null) {  
410 - return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);  
411 - }  
412 - if (userSettings.getRecordDay() <= 0) {  
413 - logger.info("录像保存事件为{}天,直接删除: {}", userSettings.getRecordDay(), file_path);  
414 - FileUtils.deleteQuietly(new File(file_path));  
415 - }else {  
416 - videoFileService.handFile(new File(file_path), app, stream);  
417 - }  
418 -  
419 - return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);  
420 - }  
421 -  
422 - /**  
423 - * 磁盘空间查询  
424 - */  
425 - @Operation(summary ="磁盘空间查询")  
426 - @ResponseBody  
427 - @GetMapping(value = "/space", produces = "application/json;charset=UTF-8")  
428 - public SpaceInfo getSpace() {  
429 - return videoFileService.getSpaceInfo();  
430 - }  
431 -  
432 - /**  
433 - * 增加推流的鉴权信息,用于录像存储使用  
434 - */  
435 - @Operation(summary ="增加推流的鉴权信息")  
436 - @Parameter(name = "app", description = "应用名", required = true)  
437 - @Parameter(name = "stream", description = "流ID", required = true)  
438 - @Parameter(name = "callId", description = "录像自鉴权ID", required = true)  
439 - @ResponseBody  
440 - @GetMapping(value = "/addStreamCallInfo", produces = "application/json;charset=UTF-8")  
441 - @PostMapping(value = "/addStreamCallInfo", produces = "application/json;charset=UTF-8")  
442 - public void addStreamCallInfo(String app, String stream, String callId) {  
443 - String key = AssistConstants.STREAM_CALL_INFO + userSettings.getId() + "_" + app + "_" + stream;  
444 - redisUtil.set(key, callId, -1);  
445 - }  
446 -  
447 - /**  
448 - * 录像文件的时长  
449 - */  
450 - @Operation(summary ="录像文件的时长")  
451 - @Parameter(name = "app", description = "应用名", required = true)  
452 - @Parameter(name = "stream", description = "流ID", required = true)  
453 - @Parameter(name = "recordIng", description = "是否录制中", required = true)  
454 - @ResponseBody  
455 - @GetMapping(value = "/file/duration", produces = "application/json;charset=UTF-8")  
456 - @PostMapping(value = "/file/duration", produces = "application/json;charset=UTF-8")  
457 - public long fileDuration( @RequestParam String app, @RequestParam String stream) {  
458 - return videoFileService.fileDuration(app, stream);  
459 - }  
460 -}  
src/main/java/top/panll/assist/controller/bean/WVPResult.java deleted 100755 → 0
1 -package top.panll.assist.controller.bean;  
2 -  
3 -  
4 -import io.swagger.v3.oas.annotations.media.Schema;  
5 -  
6 -@Schema(description = "统一返回结果")  
7 -public class WVPResult<T> {  
8 -  
9 - public WVPResult() {  
10 - }  
11 -  
12 - public WVPResult(int code, String msg, T data) {  
13 - this.code = code;  
14 - this.msg = msg;  
15 - this.data = data;  
16 - }  
17 -  
18 -  
19 - @Schema(description = "错误码,0为成功")  
20 - private int code;  
21 - @Schema(description = "描述,错误时描述错误原因")  
22 - private String msg;  
23 - @Schema(description = "数据")  
24 - private T data;  
25 -  
26 -  
27 - public static <T> WVPResult<T> success(T t, String msg) {  
28 - return new WVPResult<>(ErrorCode.SUCCESS.getCode(), msg, t);  
29 - }  
30 -  
31 - public static <T> WVPResult<T> success(T t) {  
32 - return success(t, ErrorCode.SUCCESS.getMsg());  
33 - }  
34 -  
35 - public static <T> WVPResult<T> fail(int code, String msg) {  
36 - return new WVPResult<>(code, msg, null);  
37 - }  
38 -  
39 - public static <T> WVPResult<T> fail(ErrorCode errorCode) {  
40 - return fail(errorCode.getCode(), errorCode.getMsg());  
41 - }  
42 -  
43 - public int getCode() {  
44 - return code;  
45 - }  
46 -  
47 - public void setCode(int code) {  
48 - this.code = code;  
49 - }  
50 -  
51 - public String getMsg() {  
52 - return msg;  
53 - }  
54 -  
55 - public void setMsg(String msg) {  
56 - this.msg = msg;  
57 - }  
58 -  
59 - public T getData() {  
60 - return data;  
61 - }  
62 -  
63 - public void setData(T data) {  
64 - this.data = data;  
65 - }  
66 -}  
src/main/java/top/panll/assist/dto/CloudRecordItem.java 0 → 100644
  1 +package top.panll.assist.dto;
  2 +
  3 +
  4 +/**
  5 + * 云端录像数据
  6 + */
  7 +public class CloudRecordItem {
  8 + /**
  9 + * 主键
  10 + */
  11 + private int id;
  12 +
  13 + /**
  14 + * 应用名
  15 + */
  16 + private String app;
  17 +
  18 + /**
  19 + * 流
  20 + */
  21 + private String stream;
  22 +
  23 + /**
  24 + * 健全ID
  25 + */
  26 + private String callId;
  27 +
  28 + /**
  29 + * 开始时间
  30 + */
  31 + private long startTime;
  32 +
  33 + /**
  34 + * 结束时间
  35 + */
  36 + private long endTime;
  37 +
  38 + /**
  39 + * ZLM Id
  40 + */
  41 + private String mediaServerId;
  42 +
  43 + /**
  44 + * 文件名称
  45 + */
  46 + private String fileName;
  47 +
  48 + /**
  49 + * 文件路径
  50 + */
  51 + private String filePath;
  52 +
  53 + /**
  54 + * 文件夹
  55 + */
  56 + private String folder;
  57 +
  58 + /**
  59 + * 收藏,收藏的文件不移除
  60 + */
  61 + private Boolean collect;
  62 +
  63 + /**
  64 + * 保留,收藏的文件不移除
  65 + */
  66 + private Boolean reserve;
  67 +
  68 + /**
  69 + * 文件大小
  70 + */
  71 + private long fileSize;
  72 +
  73 + /**
  74 + * 文件时长
  75 + */
  76 + private long timeLen;
  77 +
  78 + public int getId() {
  79 + return id;
  80 + }
  81 +
  82 + public void setId(int id) {
  83 + this.id = id;
  84 + }
  85 +
  86 + public String getApp() {
  87 + return app;
  88 + }
  89 +
  90 + public void setApp(String app) {
  91 + this.app = app;
  92 + }
  93 +
  94 + public String getStream() {
  95 + return stream;
  96 + }
  97 +
  98 + public void setStream(String stream) {
  99 + this.stream = stream;
  100 + }
  101 +
  102 + public String getCallId() {
  103 + return callId;
  104 + }
  105 +
  106 + public void setCallId(String callId) {
  107 + this.callId = callId;
  108 + }
  109 +
  110 + public long getStartTime() {
  111 + return startTime;
  112 + }
  113 +
  114 + public void setStartTime(long startTime) {
  115 + this.startTime = startTime;
  116 + }
  117 +
  118 + public long getEndTime() {
  119 + return endTime;
  120 + }
  121 +
  122 + public void setEndTime(long endTime) {
  123 + this.endTime = endTime;
  124 + }
  125 +
  126 + public String getMediaServerId() {
  127 + return mediaServerId;
  128 + }
  129 +
  130 + public void setMediaServerId(String mediaServerId) {
  131 + this.mediaServerId = mediaServerId;
  132 + }
  133 +
  134 + public String getFileName() {
  135 + return fileName;
  136 + }
  137 +
  138 + public void setFileName(String fileName) {
  139 + this.fileName = fileName;
  140 + }
  141 +
  142 + public String getFilePath() {
  143 + return filePath;
  144 + }
  145 +
  146 + public void setFilePath(String filePath) {
  147 + this.filePath = filePath;
  148 + }
  149 +
  150 + public String getFolder() {
  151 + return folder;
  152 + }
  153 +
  154 + public void setFolder(String folder) {
  155 + this.folder = folder;
  156 + }
  157 +
  158 + public long getFileSize() {
  159 + return fileSize;
  160 + }
  161 +
  162 + public void setFileSize(long fileSize) {
  163 + this.fileSize = fileSize;
  164 + }
  165 +
  166 + public long getTimeLen() {
  167 + return timeLen;
  168 + }
  169 +
  170 + public void setTimeLen(long timeLen) {
  171 + this.timeLen = timeLen;
  172 + }
  173 +
  174 + public Boolean getCollect() {
  175 + return collect;
  176 + }
  177 +
  178 + public void setCollect(Boolean collect) {
  179 + this.collect = collect;
  180 + }
  181 +
  182 + public Boolean getReserve() {
  183 + return reserve;
  184 + }
  185 +
  186 + public void setReserve(Boolean reserve) {
  187 + this.reserve = reserve;
  188 + }
  189 +}
src/main/java/top/panll/assist/dto/UserSettings.java
@@ -9,25 +9,28 @@ import org.springframework.stereotype.Component; @@ -9,25 +9,28 @@ import org.springframework.stereotype.Component;
9 @Component 9 @Component
10 public class UserSettings { 10 public class UserSettings {
11 11
12 - @Value("${userSettings.id}") 12 + @Value("${user-settings.id}")
13 private String id; 13 private String id;
14 14
15 - @Value("${userSettings.record}") 15 + @Value("${user-settings.record}")
16 private String record; 16 private String record;
17 17
18 - @Value("${userSettings.recordDay:7}") 18 + @Value("${user-settings.recordDay:7}")
19 private int recordDay; 19 private int recordDay;
20 20
21 - @Value("${userSettings.recordTempDay:-1}") 21 + @Value("${user-settings.recordTempDay:-1}")
22 private int recordTempDay; 22 private int recordTempDay;
23 23
24 - @Value("${userSettings.ffmpeg}") 24 + @Value("${user-settings.ffmpeg}")
25 private String ffmpeg; 25 private String ffmpeg;
26 26
27 - @Value("${userSettings.ffprobe}") 27 + @Value("${user-settings.ffprobe}")
28 private String ffprobe; 28 private String ffprobe;
29 29
30 - @Value("${userSettings.threads:2}") 30 + @Value("${user-settings.media-server-id}")
  31 + private String mediaServerId;
  32 +
  33 + @Value("${user-settings.threads:2}")
31 private int threads; 34 private int threads;
32 35
33 public String getId() { 36 public String getId() {
@@ -89,4 +92,12 @@ public class UserSettings { @@ -89,4 +92,12 @@ public class UserSettings {
89 public void setThreads(int threads) { 92 public void setThreads(int threads) {
90 this.threads = threads; 93 this.threads = threads;
91 } 94 }
  95 +
  96 + public String getMediaServerId() {
  97 + return mediaServerId;
  98 + }
  99 +
  100 + public void setMediaServerId(String mediaServerId) {
  101 + this.mediaServerId = mediaServerId;
  102 + }
92 } 103 }
src/main/java/top/panll/assist/mapper/CloudRecordServiceMapper.java 0 → 100644
  1 +package top.panll.assist.mapper;
  2 +
  3 +import org.apache.ibatis.annotations.*;
  4 +import top.panll.assist.dto.CloudRecordItem;
  5 +
  6 +import java.util.List;
  7 +
  8 +@Mapper
  9 +public interface CloudRecordServiceMapper {
  10 +
  11 + @Insert(" <script>" +
  12 + "INSERT INTO wvp_cloud_record (" +
  13 + " app," +
  14 + " stream," +
  15 + "<if test=\"callId != null\"> call_id,</if>" +
  16 + " start_time," +
  17 + " end_time," +
  18 + " media_server_id," +
  19 + " file_name," +
  20 + " folder," +
  21 + " file_path," +
  22 + " file_size," +
  23 + " time_len ) " +
  24 + "VALUES (" +
  25 + " #{app}," +
  26 + " #{stream}," +
  27 + " <if test=\"callId != null\"> #{callId},</if>" +
  28 + " #{startTime}," +
  29 + " #{endTime}," +
  30 + " #{mediaServerId}," +
  31 + " #{fileName}," +
  32 + " #{folder}," +
  33 + " #{filePath}," +
  34 + " #{fileSize}," +
  35 + " #{timeLen})" +
  36 + " </script>")
  37 + int add(CloudRecordItem cloudRecordItem);
  38 +
  39 +
  40 + @Update(" <script>" +
  41 + "update wvp_cloud_record set collect = #{collect} where file_path in " +
  42 + " <foreach collection='cloudRecordItemList' item='item' open='(' separator=',' close=')' > #{item.filePath}</foreach>" +
  43 + " </script>")
  44 + void updateCollectList(@Param("collect") boolean collect, List<CloudRecordItem> cloudRecordItemList);
  45 +
  46 + @Delete(" <script>" +
  47 + "delete from wvp_cloud_record where media_server_id=#{mediaServerId} file_path in " +
  48 + " <foreach collection='filePathList' item='item' open='(' separator=',' close=')' > #{item}</foreach>" +
  49 + " </script>")
  50 + void deleteByFileList(List<String> filePathList, @Param("mediaServerId") String mediaServerId);
  51 +
  52 +
  53 + @Select(" <script>" +
  54 + "select file_path" +
  55 + " from wvp_cloud_record " +
  56 + " where collect = false and reserve = false " +
  57 + " <if test= 'endTimeStamp != null '> and start_time &lt;= #{endTimeStamp}</if>" +
  58 + " <if test= 'callId != null '> and call_id = #{callId}</if>" +
  59 + " <if test= 'mediaServerId != null ' > and media_server_id = #{mediaServerId} </if>" +
  60 + " </script>")
  61 + List<String> queryRecordFilePathListForDelete(@Param("endTimeStamp")Long endTimeStamp, String mediaServerId);
  62 +
  63 + @Update(" <script>" +
  64 + "update wvp_cloud_record set reserve = #{reserve} where file_path in " +
  65 + " <foreach collection='cloudRecordItems' item='item' open='(' separator=',' close=')' > #{item.filePath}</foreach>" +
  66 + " </script>")
  67 + void updateReserveList(@Param("reserve") boolean reserve,List<CloudRecordItem> cloudRecordItems);
  68 +
  69 + @Update(" <script>" +
  70 + "update wvp_cloud_record set collect = #{collect} where id = #{recordId} " +
  71 + " </script>")
  72 + void changeCollectById(@Param("collect") boolean collect, @Param("recordId") Integer recordId);
  73 +
  74 + @Update(" <script>" +
  75 + "update wvp_cloud_record set reserve = #{reserve} where id = #{recordId} " +
  76 + " </script>")
  77 + void changeReserveById(@Param("reserve") boolean reserve, Integer recordId);
  78 +
  79 +
  80 + @Insert("<script> " +
  81 + "insert into wvp_cloud_record " +
  82 + "(" +
  83 + " app," +
  84 + " stream," +
  85 + " call_id," +
  86 + " start_time," +
  87 + " end_time," +
  88 + " media_server_id," +
  89 + " file_name," +
  90 + " folder," +
  91 + " file_path," +
  92 + " file_size," +
  93 + " time_len " +
  94 + ") " +
  95 + "values " +
  96 + "<foreach collection='cloudRecordItems' index='index' item='item' separator=','> " +
  97 + "(#{item.app}, #{item.stream}, #{item.callId}, #{item.startTime}, " +
  98 + "#{item.endTime}, #{item.mediaServerId}, #{item.fileName},#{item.folder}," +
  99 + "#{item.filePath}, #{item.fileSize}, #{item.timeLen}) " +
  100 + "</foreach> " +
  101 + "</script>")
  102 + int batchAdd(@Param("cloudRecordItems") List<CloudRecordItem> cloudRecordItems);
  103 +}
src/main/java/top/panll/assist/service/FFmpegExecUtils.java
@@ -18,7 +18,6 @@ import org.springframework.stereotype.Component; @@ -18,7 +18,6 @@ import org.springframework.stereotype.Component;
18 import org.springframework.util.DigestUtils; 18 import org.springframework.util.DigestUtils;
19 import top.panll.assist.dto.UserSettings; 19 import top.panll.assist.dto.UserSettings;
20 import top.panll.assist.dto.VideoFile; 20 import top.panll.assist.dto.VideoFile;
21 -import top.panll.assist.utils.RedisUtil;  
22 21
23 import java.io.BufferedWriter; 22 import java.io.BufferedWriter;
24 import java.io.File; 23 import java.io.File;
@@ -32,21 +31,7 @@ import java.util.concurrent.TimeUnit; @@ -32,21 +31,7 @@ import java.util.concurrent.TimeUnit;
32 public class FFmpegExecUtils implements InitializingBean{ 31 public class FFmpegExecUtils implements InitializingBean{
33 32
34 private final static Logger logger = LoggerFactory.getLogger(FFmpegExecUtils.class); 33 private final static Logger logger = LoggerFactory.getLogger(FFmpegExecUtils.class);
35 -// private static FFmpegExecUtils instance;  
36 -//  
37 -// public FFmpegExecUtils() {  
38 -// }  
39 -//  
40 -// public static FFmpegExecUtils getInstance(){  
41 -// if(instance==null){  
42 -// synchronized (FFmpegExecUtils.class){  
43 -// if(instance==null){  
44 -// instance=new FFmpegExecUtils();  
45 -// }  
46 -// }  
47 -// }  
48 -// return instance;  
49 -// } 34 +
50 @Autowired 35 @Autowired
51 private UserSettings userSettings; 36 private UserSettings userSettings;
52 37
src/main/java/top/panll/assist/service/FileManagerTimer.java deleted 100755 → 0
1 -package top.panll.assist.service;  
2 -  
3 -import org.apache.commons.io.FileUtils;  
4 -import org.slf4j.Logger;  
5 -import org.slf4j.LoggerFactory;  
6 -import org.springframework.beans.factory.annotation.Autowired;  
7 -import org.springframework.scheduling.annotation.Scheduled;  
8 -import org.springframework.stereotype.Component;  
9 -import org.springframework.util.StringUtils;  
10 -import top.panll.assist.dto.AssistConstants;  
11 -import top.panll.assist.dto.MergeOrCutTaskInfo;  
12 -import top.panll.assist.dto.UserSettings;  
13 -import top.panll.assist.utils.RedisUtil;  
14 -  
15 -import java.io.File;  
16 -import java.text.ParseException;  
17 -import java.text.SimpleDateFormat;  
18 -import java.util.Calendar;  
19 -import java.util.Date;  
20 -import java.util.List;  
21 -  
22 -@Component  
23 -public class FileManagerTimer {  
24 -  
25 - private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");  
26 - private final SimpleDateFormat simpleDateFormatForTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
27 -  
28 - private final static Logger logger = LoggerFactory.getLogger(FileManagerTimer.class);  
29 -  
30 - @Autowired  
31 - private UserSettings userSettings;  
32 -  
33 - @Autowired  
34 - private VideoFileService videoFileService;  
35 -  
36 - @Autowired  
37 - private RedisUtil redisUtil;  
38 -  
39 -// @Scheduled(fixedDelay = 2000) //测试 20秒执行一次  
40 - @Scheduled(cron = "0 0 0 * * ?") //每天的0点执行  
41 - public void execute(){  
42 - if (userSettings.getRecord() == null) {  
43 - return;  
44 - }  
45 - int recordDay = userSettings.getRecordDay();  
46 - Date lastDate=new Date();  
47 - Calendar lastCalendar = Calendar.getInstance();  
48 - if (recordDay > 0) {  
49 - lastCalendar.setTime(lastDate);  
50 - lastCalendar.add(Calendar.DAY_OF_MONTH, 0 - recordDay);  
51 - lastDate = lastCalendar.getTime();  
52 - }  
53 -  
54 - logger.info("[录像巡查]移除 {} 之前的文件", formatter.format(lastDate));  
55 - File recordFileDir = new File(userSettings.getRecord());  
56 - if (recordFileDir.canWrite()) {  
57 - List<File> appList = videoFileService.getAppList(false);  
58 - if (appList != null && appList.size() > 0) {  
59 - for (File appFile : appList) {  
60 - if ("download.html".equals(appFile.getName())) {  
61 - continue;  
62 - }  
63 - List<File> streamList = videoFileService.getStreamList(appFile, false);  
64 - if (streamList != null && streamList.size() > 0) {  
65 - for (File streamFile : streamList) {  
66 - // 带有sig标记文件的为收藏文件,不被自动清理任务移除  
67 - File[] signFiles = streamFile.listFiles((File dir, String name) -> {  
68 - File currentFile = new File(dir.getAbsolutePath() + File.separator + name);  
69 - return currentFile.isFile() && name.endsWith(".sign");  
70 - });  
71 - if (signFiles != null && signFiles.length > 0) {  
72 - continue;  
73 - }  
74 - List<File> dateList = videoFileService.getDateList(streamFile, null, null, false);  
75 - if (dateList != null && dateList.size() > 0) {  
76 - for (File dateFile : dateList) {  
77 - try {  
78 - Date parse = formatter.parse(dateFile.getName());  
79 - if (parse.before(lastDate)) {  
80 - boolean result = FileUtils.deleteQuietly(dateFile);  
81 - if (result) {  
82 - logger.info("[录像巡查]成功移除 {} ", dateFile.getAbsolutePath());  
83 - }else {  
84 - logger.info("[录像巡查]移除失败 {} ", dateFile.getAbsolutePath());  
85 - }  
86 - }  
87 - } catch (ParseException e) {  
88 - e.printStackTrace();  
89 - }  
90 - }  
91 - }  
92 - if (streamFile.listFiles() == null || streamFile.listFiles().length == 0) {  
93 - boolean result = FileUtils.deleteQuietly(streamFile);  
94 - if (result) {  
95 - logger.info("[录像巡查]成功移除 {} ", streamFile.getAbsolutePath());  
96 - }else {  
97 - logger.info("[录像巡查]移除失败 {} ", streamFile.getAbsolutePath());  
98 - }  
99 - }  
100 - }  
101 - }  
102 - if (appFile.listFiles() == null || appFile.listFiles().length == 0) {  
103 - boolean result = FileUtils.deleteQuietly(appFile);  
104 - if (result) {  
105 - logger.info("[录像巡查]成功移除 {} ", appFile.getAbsolutePath());  
106 - }else {  
107 - logger.info("[录像巡查]移除失败 {} ", appFile.getAbsolutePath());  
108 - }  
109 - }  
110 - }  
111 - }  
112 - }  
113 - // 清理任务临时文件  
114 - int recordTempDay = userSettings.getRecordTempDay();  
115 - Date lastTempDate = new Date();  
116 - Calendar lastTempCalendar = Calendar.getInstance();  
117 - lastTempCalendar.setTime(lastTempDate);  
118 - lastTempCalendar.add(Calendar.DAY_OF_MONTH, 0 - recordTempDay);  
119 - lastTempDate = lastTempCalendar.getTime();  
120 - logger.info("[录像巡查]移除合并任务临时文件 {} 之前的文件", formatter.format(lastTempDate));  
121 - File recordTempFile = new File(userSettings.getRecord() + "recordTemp");  
122 - if (recordTempFile.exists() && recordTempFile.isDirectory() && recordTempFile.canWrite()) {  
123 - File[] tempFiles = recordTempFile.listFiles();  
124 - for (File tempFile : tempFiles) {  
125 - if (tempFile.isDirectory() && new Date(tempFile.lastModified()).before(lastTempDate)) {  
126 - boolean result = FileUtils.deleteQuietly(tempFile);  
127 - if (result) {  
128 - logger.info("[录像巡查]成功移除合并任务临时文件 {} ", tempFile.getAbsolutePath());  
129 - }else {  
130 - logger.info("[录像巡查]合并任务临时文件移除失败 {} ", tempFile.getAbsolutePath());  
131 - }  
132 - }  
133 - }  
134 - }  
135 - // 清理redis记录  
136 - String key = String.format("%S_%S_*_*_*", AssistConstants.MERGEORCUT, userSettings.getId());  
137 - List<Object> taskKeys = redisUtil.scan(key);  
138 - for (Object taskKeyObj : taskKeys) {  
139 - String taskKey = (String) taskKeyObj;  
140 - MergeOrCutTaskInfo mergeOrCutTaskInfo = (MergeOrCutTaskInfo)redisUtil.get(taskKey);  
141 - try {  
142 - if (StringUtils.isEmpty(mergeOrCutTaskInfo.getCreateTime())  
143 - || simpleDateFormatForTime.parse(mergeOrCutTaskInfo.getCreateTime()).before(lastTempDate)) {  
144 - redisUtil.del(taskKey);  
145 - }  
146 - } catch (ParseException e) {  
147 - e.printStackTrace();  
148 - }  
149 - }  
150 - }  
151 -}  
src/main/java/top/panll/assist/service/VideoFileService.java deleted 100755 → 0
1 -package top.panll.assist.service;  
2 -  
3 -import net.bramp.ffmpeg.FFprobe;  
4 -import net.bramp.ffmpeg.probe.FFmpegProbeResult;  
5 -import net.bramp.ffmpeg.progress.Progress;  
6 -import org.apache.commons.io.FileUtils;  
7 -import org.slf4j.Logger;  
8 -import org.slf4j.LoggerFactory;  
9 -import org.springframework.beans.factory.annotation.Autowired;  
10 -import org.springframework.data.redis.core.RedisTemplate;  
11 -import org.springframework.stereotype.Service;  
12 -import org.springframework.util.DigestUtils;  
13 -import top.panll.assist.dto.*;  
14 -import top.panll.assist.utils.RedisUtil;  
15 -import top.panll.assist.utils.DateUtils;  
16 -  
17 -import java.io.File;  
18 -import java.io.IOException;  
19 -import java.nio.file.Files;  
20 -import java.nio.file.Path;  
21 -import java.nio.file.Paths;  
22 -import java.nio.file.attribute.BasicFileAttributes;  
23 -import java.text.ParseException;  
24 -import java.text.SimpleDateFormat;  
25 -import java.util.*;  
26 -  
27 -@Service  
28 -public class VideoFileService {  
29 -  
30 - private final static Logger logger = LoggerFactory.getLogger(VideoFileService.class);  
31 -  
32 - @Autowired  
33 - private UserSettings userSettings;  
34 -  
35 - @Autowired  
36 - private RedisUtil redisUtil;  
37 -  
38 - @Autowired  
39 - private FFmpegExecUtils ffmpegExecUtils;  
40 -  
41 -  
42 -  
43 - private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");  
44 - private final SimpleDateFormat simpleDateFormatForTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
45 -  
46 - public List<File> getAppList(Boolean sort) {  
47 - File recordFile = new File(userSettings.getRecord());  
48 - if (recordFile.isDirectory()) {  
49 - File[] files = recordFile.listFiles((File dir, String name) -> {  
50 - File currentFile = new File(dir.getAbsolutePath() + File.separator + name);  
51 - return currentFile.isDirectory() && !name.equals("recordTemp");  
52 - });  
53 - List<File> result = Arrays.asList(files);  
54 - if (sort != null && sort) {  
55 - Collections.sort(result);  
56 - }  
57 - return result;  
58 - }else {  
59 - return null;  
60 - }  
61 - }  
62 -  
63 - public SpaceInfo getSpaceInfo(){  
64 - File recordFile = new File(userSettings.getRecord());  
65 - SpaceInfo spaceInfo = new SpaceInfo();  
66 - spaceInfo.setFree(recordFile.getFreeSpace());  
67 - spaceInfo.setTotal(recordFile.getTotalSpace());  
68 - return spaceInfo;  
69 - }  
70 -  
71 - public List<File> getStreamList(String app, Boolean sort) {  
72 - File appFile = new File(userSettings.getRecord() + File.separator + app);  
73 - return getStreamList(appFile, sort);  
74 - }  
75 -  
76 - public List<File> getStreamList(File appFile, Boolean sort) {  
77 - if (appFile != null && appFile.isDirectory()) {  
78 - File[] files = appFile.listFiles((File dir, String name) -> {  
79 - File currentFile = new File(dir.getAbsolutePath() + File.separator + name);  
80 - return currentFile.isDirectory();  
81 - });  
82 - List<File> result = Arrays.asList(files);  
83 - if (sort != null && sort) {  
84 - Collections.sort(result);  
85 - }  
86 - return result;  
87 - }else {  
88 - return null;  
89 - }  
90 - }  
91 -  
92 - /**  
93 - * 对视频文件重命名  
94 - */  
95 - public void handFile(File file,String app, String stream) {  
96 - VideoFile videoFile = VideoFileFactory.createFile(ffmpegExecUtils, file);  
97 - if (videoFile == null || videoFile.isTargetFormat()) {  
98 - return;  
99 - }  
100 -  
101 - SimpleDateFormat dateFormat = new SimpleDateFormat("HHmmss");  
102 -  
103 - String key = AssistConstants.STREAM_CALL_INFO + userSettings.getId() + "_" + app + "_" + stream;  
104 - String callId = (String) redisUtil.get(key);  
105 -  
106 - String streamNew = (callId == null? stream : stream + "_" + callId);  
107 - File newPath = new File(userSettings.getRecord() + File.separator + app + File.separator + streamNew  
108 - + File.separator + DateUtils.getDateStr(videoFile.getStartTime()));  
109 - if (!newPath.exists()) {  
110 - newPath.mkdirs();  
111 - }  
112 -  
113 - String newName = newPath.getAbsolutePath() + File.separator+ dateFormat.format(videoFile.getStartTime())  
114 - + "-" + dateFormat.format(videoFile.getEndTime()) + ".mp4";  
115 - logger.info("[处理文件] {}->{}", file.getAbsolutePath(), newName);  
116 - boolean renameTo = file.renameTo(new File(newName));  
117 - if (!renameTo) {  
118 - logger.info("[处理文件]文件重命名失败 {}->{}", file.getAbsolutePath(), newName);  
119 - }  
120 - }  
121 -  
122 - public List<Map<String, String>> getList() {  
123 -  
124 - List<Map<String, String>> result = new ArrayList<>();  
125 -  
126 - List<File> appList = getAppList(true);  
127 - if (appList != null && appList.size() > 0) {  
128 - for (File appFile : appList) {  
129 - if (appFile.isDirectory()) {  
130 - List<File> streamList = getStreamList(appFile.getName(), true);  
131 - if (streamList != null && streamList.size() > 0) {  
132 - for (File streamFile : streamList) {  
133 - Map<String, String> data = new HashMap<>();  
134 - data.put("app", appFile.getName());  
135 - data.put("stream", streamFile.getName());  
136 -  
137 - BasicFileAttributes bAttributes = null;  
138 - try {  
139 - bAttributes = Files.readAttributes(streamFile.toPath(),  
140 - BasicFileAttributes.class);  
141 - } catch (IOException e) {  
142 - e.printStackTrace();  
143 - }  
144 - data.put("time", simpleDateFormatForTime.format(new Date(bAttributes.lastModifiedTime().toMillis())));  
145 - result.add(data);  
146 - }  
147 - }  
148 - }  
149 - }  
150 - }  
151 - result.sort((Map f1, Map f2)->{  
152 - Date time1 = null;  
153 - Date time2 = null;  
154 - try {  
155 - time1 = simpleDateFormatForTime.parse(f1.get("time").toString());  
156 - time2 = simpleDateFormatForTime.parse(f2.get("time").toString());  
157 - } catch (ParseException e) {  
158 - logger.error("时间格式化失败", e);  
159 - }  
160 - return time1.compareTo(time2) * -1;  
161 - });  
162 - return result;  
163 - }  
164 -  
165 - /**  
166 - * 获取制定推流的指定时间段内的推流  
167 - * @param app  
168 - * @param stream  
169 - * @param startTime  
170 - * @param endTime  
171 - * @return  
172 - */  
173 - public List<File> getFilesInTime(String app, String stream, Date startTime, Date endTime){  
174 -  
175 - List<File> result = new ArrayList<>();  
176 - if (app == null || stream == null) {  
177 - return result;  
178 - }  
179 -  
180 - SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HHmmss");  
181 - SimpleDateFormat formatterForDate = new SimpleDateFormat("yyyy-MM-dd");  
182 - String startTimeStr = null;  
183 - String endTimeStr = null;  
184 - if (startTime != null) {  
185 - startTimeStr = formatter.format(startTime);  
186 - }  
187 - if (endTime != null) {  
188 - endTimeStr = formatter.format(endTime);  
189 - }  
190 -  
191 - logger.debug("获取[app: {}, stream: {}, statime: {}, endTime: {}]的视频", app, stream,  
192 - startTimeStr, endTimeStr);  
193 -  
194 - File recordFile = new File(userSettings.getRecord());  
195 - File streamFile = new File(recordFile.getAbsolutePath() + File.separator + app + File.separator + stream + File.separator);  
196 - if (!streamFile.exists()) {  
197 - logger.warn("获取[app: {}, stream: {}, statime: {}, endTime: {}]的视频时未找到目录: {}", app, stream,  
198 - startTimeStr, endTimeStr, stream);  
199 - return null;  
200 - }  
201 -  
202 - File[] dateFiles = streamFile.listFiles((File dir, String name) -> {  
203 - Date fileDate = null;  
204 - Date startDate = null;  
205 - Date endDate = null;  
206 - if (new File(dir + File.separator + name).isFile()) {  
207 - return false;  
208 - }  
209 - if (startTime != null) {  
210 - startDate = new Date(startTime.getTime() - ((startTime.getTime() + 28800000) % (86400000)));  
211 - }  
212 - if (endTime != null) {  
213 - endDate = new Date(endTime.getTime() - ((endTime.getTime() + 28800000) % (86400000)));  
214 - }  
215 - try {  
216 - fileDate = formatterForDate.parse(name);  
217 - } catch (ParseException e) {  
218 - logger.error("过滤日期文件时异常: {}-{}", name, e.getMessage());  
219 - return false;  
220 - }  
221 - boolean filterResult = true;  
222 -  
223 - if (startDate != null) {  
224 - filterResult = filterResult && DateUtils.getStartOfDay(startDate).compareTo(fileDate) <= 0;  
225 - }  
226 -  
227 - if (endDate != null) {  
228 - filterResult = filterResult && DateUtils.getEndOfDay(endDate).compareTo(fileDate) >= 0;  
229 - }  
230 -  
231 - return filterResult ;  
232 - });  
233 -  
234 - if (dateFiles != null && dateFiles.length > 0) {  
235 - for (File dateFile : dateFiles) {  
236 - File[] files = dateFile.listFiles((File dir, String name) ->{  
237 - File currentFile = new File(dir + File.separator + name);  
238 - VideoFile videoFile = VideoFileFactory.createFile(ffmpegExecUtils, currentFile);  
239 - if (videoFile == null ) {  
240 - return false;  
241 - }else {  
242 - if (!videoFile.isTargetFormat()) {  
243 - return false;  
244 - }  
245 - if (startTime == null && endTime == null) {  
246 - return true;  
247 - }else if (startTime == null && endTime != null) {  
248 - return videoFile.getEndTime().before(endTime)  
249 - || videoFile.getEndTime().equals(endTime)  
250 - || (videoFile.getEndTime().after(endTime) && videoFile.getStartTime().before(endTime));  
251 - }else if (startTime != null && endTime == null) {  
252 - return videoFile.getStartTime().after(startTime)  
253 - || videoFile.getStartTime().equals(startTime)  
254 - || (videoFile.getStartTime().before(startTime) && videoFile.getEndTime().after(startTime));  
255 - }else {  
256 - return videoFile.getStartTime().after(startTime)  
257 - || videoFile.getStartTime().equals(startTime)  
258 - || (videoFile.getStartTime().before(startTime) && videoFile.getEndTime().after(startTime))  
259 - || videoFile.getEndTime().before(endTime)  
260 - || videoFile.getEndTime().equals(endTime)  
261 - || (videoFile.getEndTime().after(endTime) && videoFile.getStartTime().before(endTime));  
262 - }  
263 - }  
264 - });  
265 - if (files != null && files.length > 0) {  
266 - result.addAll(Arrays.asList(files));  
267 - }  
268 - }  
269 - }  
270 - if (!result.isEmpty()) {  
271 - result.sort((File f1, File f2) -> {  
272 - VideoFile videoFile1 = VideoFileFactory.createFile(ffmpegExecUtils, f1);  
273 - VideoFile videoFile2 = VideoFileFactory.createFile(ffmpegExecUtils, f2);  
274 - if (videoFile1 == null || !videoFile1.isTargetFormat() || videoFile2 == null || !videoFile2.isTargetFormat()) {  
275 - logger.warn("[根据时间获取视频文件] 排序错误,文件错误: {}/{}", f1.getName(), f2.getName());  
276 - return 0;  
277 - }  
278 - return videoFile1.getStartTime().compareTo(videoFile2.getStartTime());  
279 - });  
280 - }  
281 - return result;  
282 - }  
283 -  
284 -  
285 - public String mergeOrCut(String app, String stream, Date startTime, Date endTime, String remoteHost) {  
286 - List<File> filesInTime = this.getFilesInTime(app, stream, startTime, endTime);  
287 - if (filesInTime== null || filesInTime.isEmpty()){  
288 - logger.info("此时间段未未找到视频文件, {}/{} {}->{}", app, stream,  
289 - startTime == null? null:DateUtils.getDateTimeStr(startTime),  
290 - endTime == null? null:DateUtils.getDateTimeStr(endTime));  
291 - return null;  
292 - }  
293 - String taskId = DigestUtils.md5DigestAsHex(String.valueOf(System.currentTimeMillis()).getBytes());  
294 - logger.info("[录像合并] 开始合并,APP:{}, STREAM: {}, 任务ID:{}", app, stream, taskId);  
295 - String destDir = "recordTemp" + File.separator + taskId + File.separator + app;  
296 - File recordFile = new File(userSettings.getRecord() + destDir );  
297 - if (!recordFile.exists()) {  
298 - recordFile.mkdirs();  
299 - }  
300 - MergeOrCutTaskInfo mergeOrCutTaskInfo = new MergeOrCutTaskInfo();  
301 - mergeOrCutTaskInfo.setId(taskId);  
302 - mergeOrCutTaskInfo.setApp(app);  
303 - mergeOrCutTaskInfo.setStream(stream);  
304 - mergeOrCutTaskInfo.setCreateTime(simpleDateFormatForTime.format(System.currentTimeMillis()));  
305 - if(startTime != null) {  
306 - mergeOrCutTaskInfo.setStartTime(simpleDateFormatForTime.format(startTime));  
307 - }else {  
308 - String startTimeInFile = filesInTime.get(0).getParentFile().getName() + " "  
309 - + filesInTime.get(0).getName().split("-")[0];  
310 - mergeOrCutTaskInfo.setStartTime(startTimeInFile);  
311 - }  
312 - if(endTime != null) {  
313 - mergeOrCutTaskInfo.setEndTime(simpleDateFormatForTime.format(endTime));  
314 - }else {  
315 - String endTimeInFile = filesInTime.get(filesInTime.size()- 1).getParentFile().getName() + " "  
316 - + filesInTime.get(filesInTime.size()- 1).getName().split("-")[1];  
317 - mergeOrCutTaskInfo.setEndTime(endTimeInFile);  
318 - }  
319 - if (filesInTime.size() == 1) {  
320 -  
321 - // 文件只有一个则不合并,直接复制过去  
322 - mergeOrCutTaskInfo.setPercentage("1");  
323 - // 处理文件路径  
324 - String recordFileResultPath = recordFile.getAbsolutePath() + File.separator + stream + ".mp4";  
325 - Path relativize = Paths.get(userSettings.getRecord()).relativize(Paths.get(recordFileResultPath));  
326 - try {  
327 - Files.copy(filesInTime.get(0).toPath(), Paths.get(recordFileResultPath));  
328 - } catch (IOException e) {  
329 - e.printStackTrace();  
330 - logger.info("[录像合并] 失败,APP:{}, STREAM: {}, 任务ID:{}", app, stream, taskId);  
331 - return taskId;  
332 - }  
333 - mergeOrCutTaskInfo.setRecordFile("/download/" + relativize.toString());  
334 - if (remoteHost != null) {  
335 - mergeOrCutTaskInfo.setDownloadFile(remoteHost + "/download.html?url=download/" + relativize);  
336 - mergeOrCutTaskInfo.setPlayFile(remoteHost + "/download/" + relativize);  
337 - }  
338 - String key = String.format("%S_%S_%S_%S_%S", AssistConstants.MERGEORCUT , userSettings.getId(), mergeOrCutTaskInfo.getApp(), mergeOrCutTaskInfo.getStream(), mergeOrCutTaskInfo.getId());  
339 - redisUtil.set(key, mergeOrCutTaskInfo);  
340 - logger.info("[录像合并] 合并完成,APP:{}, STREAM: {}, 任务ID:{}", app, stream, taskId);  
341 - }else {  
342 - ffmpegExecUtils.mergeOrCutFile(filesInTime, recordFile, stream, (status, percentage, result)->{  
343 - // 发出redis通知  
344 - if (status.equals(Progress.Status.END.name())) {  
345 - mergeOrCutTaskInfo.setPercentage("1");  
346 -  
347 - // 处理文件路径  
348 - Path relativize = Paths.get(userSettings.getRecord()).relativize(Paths.get(result));  
349 - mergeOrCutTaskInfo.setRecordFile(relativize.toString());  
350 - if (remoteHost != null) {  
351 - mergeOrCutTaskInfo.setDownloadFile(remoteHost + "/download.html?url=download/" + relativize);  
352 - mergeOrCutTaskInfo.setPlayFile(remoteHost + "/download/" + relativize);  
353 - }  
354 - logger.info("[录像合并] 合并完成,APP:{}, STREAM: {}, 任务ID:{}", app, stream, taskId);  
355 - }else {  
356 - mergeOrCutTaskInfo.setPercentage(percentage + "");  
357 - }  
358 - String key = String.format("%S_%S_%S_%S_%S", AssistConstants.MERGEORCUT, userSettings.getId(), mergeOrCutTaskInfo.getApp(), mergeOrCutTaskInfo.getStream(), mergeOrCutTaskInfo.getId());  
359 - redisUtil.set(key, mergeOrCutTaskInfo);  
360 - });  
361 - }  
362 -  
363 - return taskId;  
364 - }  
365 -  
366 - /**  
367 - * 获取指定时间的日期文件夹  
368 - * @param app  
369 - * @param stream  
370 - * @param year  
371 - * @param month  
372 - * @return  
373 - */  
374 - public List<File> getDateList(String app, String stream, Integer year, Integer month, Boolean sort) {  
375 - File recordFile = new File(userSettings.getRecord());  
376 - File streamFile = new File(recordFile.getAbsolutePath() + File.separator + app + File.separator + stream);  
377 - return getDateList(streamFile, year, month, sort);  
378 - }  
379 - public List<File> getDateList(File streamFile, Integer year, Integer month, Boolean sort) {  
380 - if (!streamFile.exists() && streamFile.isDirectory()) {  
381 - logger.warn("获取[]的视频时未找到目录: {}",streamFile.getName());  
382 - return null;  
383 - }  
384 - File[] dateFiles = streamFile.listFiles((File dir, String name)->{  
385 - File currentFile = new File(dir.getAbsolutePath() + File.separator + name);  
386 - if (!currentFile.isDirectory()){  
387 - return false;  
388 - }  
389 - Date date = null;  
390 - try {  
391 - date = simpleDateFormat.parse(name);  
392 - } catch (ParseException e) {  
393 - logger.error("格式化时间{}错误", name);  
394 - return false;  
395 - }  
396 - Calendar c = Calendar.getInstance();  
397 - c.setTime(date);  
398 - int y = c.get(Calendar.YEAR);  
399 - int m = c.get(Calendar.MONTH) + 1;  
400 - if (year != null) {  
401 - if (month != null) {  
402 - return y == year && m == month;  
403 - }else {  
404 - return y == year;  
405 - }  
406 - }else {  
407 - return true;  
408 - }  
409 -  
410 - });  
411 - if (dateFiles == null) {  
412 - return new ArrayList<>();  
413 - }  
414 - List<File> dateFileList = Arrays.asList(dateFiles);  
415 - if (sort != null && sort) {  
416 - dateFileList.sort((File f1, File f2)->{  
417 - int sortResult = 0;  
418 -  
419 - try {  
420 - sortResult = simpleDateFormat.parse(f1.getName()).compareTo(simpleDateFormat.parse(f2.getName()));  
421 - } catch (ParseException e) {  
422 - logger.error("格式化时间{}/{}错误", f1.getName(), f2.getName());  
423 - }  
424 - return sortResult;  
425 - });  
426 - }  
427 -  
428 - return dateFileList;  
429 - }  
430 -  
431 - public List<MergeOrCutTaskInfo> getTaskListForDownload(Boolean idEnd, String app, String stream, String taskId) {  
432 - ArrayList<MergeOrCutTaskInfo> result = new ArrayList<>();  
433 - if (app == null) {  
434 - app = "*";  
435 - }  
436 - if (stream == null) {  
437 - stream = "*";  
438 - }  
439 - if (taskId == null) {  
440 - taskId = "*";  
441 - }  
442 - List<Object> taskCatch = redisUtil.scan(String.format("%S_%S_%S_%S_%S", AssistConstants.MERGEORCUT,  
443 - userSettings.getId(), app, stream, taskId));  
444 - for (int i = 0; i < taskCatch.size(); i++) {  
445 - String keyItem = taskCatch.get(i).toString();  
446 - MergeOrCutTaskInfo mergeOrCutTaskInfo = (MergeOrCutTaskInfo)redisUtil.get(keyItem);  
447 - if (mergeOrCutTaskInfo != null && mergeOrCutTaskInfo.getPercentage() != null){  
448 - if (idEnd != null ) {  
449 - if (idEnd) {  
450 - if (Double.parseDouble(mergeOrCutTaskInfo.getPercentage()) == 1){  
451 - result.add(mergeOrCutTaskInfo);  
452 - }  
453 - }else {  
454 - if (Double.parseDouble(mergeOrCutTaskInfo.getPercentage()) < 1){  
455 - result.add((MergeOrCutTaskInfo)redisUtil.get(keyItem));  
456 - }  
457 - }  
458 - }else {  
459 - result.add((MergeOrCutTaskInfo)redisUtil.get(keyItem));  
460 - }  
461 - }  
462 - }  
463 - result.sort((MergeOrCutTaskInfo m1, MergeOrCutTaskInfo m2)->{  
464 - int sortResult = 0;  
465 - try {  
466 - sortResult = simpleDateFormatForTime.parse(m1.getCreateTime()).compareTo(simpleDateFormatForTime.parse(m2.getCreateTime()));  
467 - if (sortResult == 0) {  
468 - sortResult = simpleDateFormatForTime.parse(m1.getStartTime()).compareTo(simpleDateFormatForTime.parse(m2.getStartTime()));  
469 - }  
470 - if (sortResult == 0) {  
471 - sortResult = simpleDateFormatForTime.parse(m1.getEndTime()).compareTo(simpleDateFormatForTime.parse(m2.getEndTime()));  
472 - }  
473 - } catch (ParseException e) {  
474 - e.printStackTrace();  
475 - }  
476 - return sortResult * -1;  
477 - });  
478 -  
479 - return result;  
480 - }  
481 -  
482 - public boolean collection(String app, String stream, String type) {  
483 - File streamFile = new File(userSettings.getRecord() + File.separator + app + File.separator + stream);  
484 - boolean result = false;  
485 - if (streamFile.exists() && streamFile.isDirectory() && streamFile.canWrite()) {  
486 - File signFile = new File(streamFile.getAbsolutePath() + File.separator + type + ".sign");  
487 - try {  
488 - result = signFile.createNewFile();  
489 - } catch (IOException e) {  
490 - logger.error("[收藏文件]失败,{}/{}", app, stream);  
491 - }  
492 - }  
493 - return result;  
494 - }  
495 -  
496 - public boolean removeCollection(String app, String stream, String type) {  
497 - File signFile = new File(userSettings.getRecord() + File.separator + app + File.separator + stream + File.separator + type + ".sign");  
498 - boolean result = false;  
499 - if (signFile.exists() && signFile.isFile()) {  
500 - result = signFile.delete();  
501 - }  
502 - return result;  
503 - }  
504 -  
505 - public List<SignInfo> getCollectionList(String app, String stream, String type) {  
506 - List<File> appList = this.getAppList(true);  
507 - List<SignInfo> result = new ArrayList<>();  
508 - if (appList.size() > 0) {  
509 - for (File appFile : appList) {  
510 - if (app != null) {  
511 - if (!app.equals(appFile.getName())) {  
512 - continue;  
513 - }  
514 - }  
515 - List<File> streamList = getStreamList(appFile, true);  
516 - if (streamList.size() > 0) {  
517 - for (File streamFile : streamList) {  
518 - if (stream != null) {  
519 - if (!stream.equals(streamFile.getName())) {  
520 - continue;  
521 - }  
522 - }  
523 -  
524 - if (type != null) {  
525 - File signFile = new File(streamFile.getAbsolutePath() + File.separator + type + ".sign");  
526 - if (signFile.exists()) {  
527 - SignInfo signInfo = new SignInfo();  
528 - signInfo.setApp(appFile.getName());  
529 - signInfo.setStream(streamFile.getName());  
530 - signInfo.setType(type);  
531 - result.add(signInfo);  
532 - }  
533 - }else {  
534 - streamFile.listFiles((File dir, String name) -> {  
535 - File currentFile = new File(dir.getAbsolutePath() + File.separator + name);  
536 - if (currentFile.isFile() && name.endsWith(".sign")){  
537 - String currentType = name.substring(0, name.length() - ".sign".length());  
538 - SignInfo signInfo = new SignInfo();  
539 - signInfo.setApp(appFile.getName());  
540 - signInfo.setStream(streamFile.getName());  
541 - signInfo.setType(currentType);  
542 - result.add(signInfo);  
543 - }  
544 - return false;  
545 - });  
546 - }  
547 - }  
548 - }  
549 - }  
550 - }  
551 - return result;  
552 - }  
553 -  
554 - public long fileDuration(String app, String stream) {  
555 - List<File> allFiles = getFilesInTime(app, stream, null, null);  
556 - long durationResult = 0;  
557 - if (allFiles != null && allFiles.size() > 0) {  
558 - for (File file : allFiles) {  
559 - try {  
560 - durationResult += ffmpegExecUtils.duration(file);  
561 - } catch (IOException e) {  
562 - logger.error("获取{}视频时长错误:{}", file.getAbsolutePath(), e.getMessage());  
563 - }  
564 - }  
565 - }  
566 - return durationResult;  
567 - }  
568 -}  
src/main/java/top/panll/assist/utils/DateUtils.java
1 package top.panll.assist.utils; 1 package top.panll.assist.utils;
2 2
  3 +import java.text.ParseException;
3 import java.text.SimpleDateFormat; 4 import java.text.SimpleDateFormat;
4 import java.time.Instant; 5 import java.time.Instant;
5 import java.time.LocalDateTime; 6 import java.time.LocalDateTime;
6 import java.time.LocalTime; 7 import java.time.LocalTime;
7 import java.time.ZoneId; 8 import java.time.ZoneId;
8 import java.time.format.DateTimeFormatter; 9 import java.time.format.DateTimeFormatter;
  10 +import java.time.temporal.TemporalAccessor;
9 import java.util.Date; 11 import java.util.Date;
10 import java.util.Locale; 12 import java.util.Locale;
11 13
@@ -13,10 +15,14 @@ public class DateUtils { @@ -13,10 +15,14 @@ public class DateUtils {
13 15
14 public static final String PATTERNForDateTime = "yyyy-MM-dd HH:mm:ss"; 16 public static final String PATTERNForDateTime = "yyyy-MM-dd HH:mm:ss";
15 17
  18 + public static final String PATTERNForTime = "HH:mm:ss";
  19 +
16 public static final String PATTERNForDate = "yyyy-MM-dd"; 20 public static final String PATTERNForDate = "yyyy-MM-dd";
17 21
18 public static final String zoneStr = "Asia/Shanghai"; 22 public static final String zoneStr = "Asia/Shanghai";
19 23
  24 + public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERNForDateTime, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
  25 + public static final DateTimeFormatter formatterForTime = DateTimeFormatter.ofPattern(PATTERNForTime, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
20 26
21 27
22 // 获得某天最大时间 2020-02-19 23:59:59 28 // 获得某天最大时间 2020-02-19 23:59:59
@@ -39,8 +45,38 @@ public class DateUtils { @@ -39,8 +45,38 @@ public class DateUtils {
39 } 45 }
40 46
41 public static String getDateTimeStr(Date date) { 47 public static String getDateTimeStr(Date date) {
42 - SimpleDateFormat formatter = new SimpleDateFormat(PATTERNForDateTime); 48 + SimpleDateFormat formatter = new SimpleDateFormat(PATTERNForDateTime);
43 return formatter.format(date); 49 return formatter.format(date);
44 } 50 }
  51 + public static String getTimeStr(Long dateTime) {
  52 + SimpleDateFormat formatter = new SimpleDateFormat(PATTERNForTime);
  53 + return formatter.format(new Date(dateTime));
  54 + }
  55 +
  56 + public static boolean checkDateFormat(String dateStr) {
  57 + SimpleDateFormat formatter = new SimpleDateFormat(PATTERNForDate);
  58 + try {
  59 + formatter.parse(dateStr);
  60 + return true;
  61 + } catch (ParseException e) {
  62 + return false;
  63 + }
  64 + }
  65 +
  66 + public static boolean checkDateTimeFormat(String dateStr) {
  67 + SimpleDateFormat formatter = new SimpleDateFormat(PATTERNForDateTime);
  68 + try {
  69 + formatter.parse(dateStr);
  70 + return true;
  71 + } catch (ParseException e) {
  72 + return false;
  73 + }
  74 + }
  75 +
  76 + public static long yyyy_MM_dd_HH_mm_ssToTimestamp(String formatTime) {
  77 + TemporalAccessor temporalAccessor = formatter.parse(formatTime);
  78 + Instant instant = Instant.from(temporalAccessor);
  79 + return instant.getEpochSecond();
  80 + }
45 81
46 } 82 }
src/main/java/top/panll/assist/utils/PageInfo.java deleted 100755 → 0
1 -package top.panll.assist.utils;  
2 -  
3 -import java.util.ArrayList;  
4 -import java.util.List;  
5 -  
6 -public class PageInfo<T> {  
7 - //当前页  
8 - private int pageNum;  
9 - //每页的数量  
10 - private int pageSize;  
11 - //当前页的数量  
12 - private int size;  
13 - //总页数  
14 - private int pages;  
15 - //总数  
16 - private int total;  
17 -  
18 - private List<T> resultData;  
19 -  
20 - private List<T> list;  
21 -  
22 - public PageInfo(List<T> resultData) {  
23 - this.resultData = resultData;  
24 - }  
25 -  
26 - public void startPage(int page, int count) {  
27 - if (count <= 0) count = 10;  
28 - if (page <= 0) page = 1;  
29 - this.pageNum = page;  
30 - this.pageSize = count;  
31 - this.total = resultData.size();  
32 -  
33 - this.pages = total%count == 0 ? total/count : total/count + 1;  
34 - int fromIndx = (page - 1) * count;  
35 - if ( fromIndx > this.total - 1) {  
36 - this.list = new ArrayList<>();  
37 - this.size = 0;  
38 - return;  
39 - }  
40 -  
41 - int toIndx = page * count;  
42 - if (toIndx > this.total) {  
43 - toIndx = this.total;  
44 - }  
45 - this.list = this.resultData.subList(fromIndx, toIndx);  
46 - this.size = this.list.size();  
47 - }  
48 -  
49 - public int getPageNum() {  
50 - return pageNum;  
51 - }  
52 -  
53 - public void setPageNum(int pageNum) {  
54 - this.pageNum = pageNum;  
55 - }  
56 -  
57 - public int getPageSize() {  
58 - return pageSize;  
59 - }  
60 -  
61 - public void setPageSize(int pageSize) {  
62 - this.pageSize = pageSize;  
63 - }  
64 -  
65 - public int getSize() {  
66 - return size;  
67 - }  
68 -  
69 - public void setSize(int size) {  
70 - this.size = size;  
71 - }  
72 -  
73 - public int getPages() {  
74 - return pages;  
75 - }  
76 -  
77 - public void setPages(int pages) {  
78 - this.pages = pages;  
79 - }  
80 -  
81 - public int getTotal() {  
82 - return total;  
83 - }  
84 -  
85 - public void setTotal(int total) {  
86 - this.total = total;  
87 - }  
88 -  
89 - public List<T> getList() {  
90 - return list;  
91 - }  
92 -  
93 - public void setList(List<T> list) {  
94 - this.list = list;  
95 - }  
96 -}  
src/main/java/top/panll/assist/utils/RedisUtil.java deleted 100755 → 0
1 -package top.panll.assist.utils;  
2 -  
3 -import org.springframework.beans.factory.annotation.Autowired;  
4 -import org.springframework.data.redis.core.*;  
5 -import org.springframework.stereotype.Component;  
6 -import org.springframework.util.CollectionUtils;  
7 -  
8 -import java.util.*;  
9 -import java.util.concurrent.TimeUnit;  
10 -  
11 -/**  
12 - * @Description:Redis工具类  
13 - * @author: swwheihei  
14 - * @date: 2020年5月6日 下午8:27:29  
15 - */  
16 -@Component  
17 -@SuppressWarnings(value = {"rawtypes", "unchecked"})  
18 -public class RedisUtil {  
19 -  
20 - @Autowired  
21 - private RedisTemplate<Object, Object> redisTemplate;  
22 -  
23 - /**  
24 - * 指定缓存失效时间  
25 - * @param key 键  
26 - * @param time 时间(秒)  
27 - * @return true / false  
28 - */  
29 - public boolean expire(String key, long time) {  
30 - try {  
31 - if (time > 0) {  
32 - redisTemplate.expire(key, time, TimeUnit.SECONDS);  
33 - }  
34 - return true;  
35 - } catch (Exception e) {  
36 - e.printStackTrace();  
37 - return false;  
38 - }  
39 -  
40 - }  
41 -  
42 - /**  
43 - * 根据 key 获取过期时间  
44 - * @param key 键  
45 - * @return  
46 - */  
47 - public long getExpire(String key) {  
48 - return redisTemplate.getExpire(key, TimeUnit.SECONDS);  
49 - }  
50 -  
51 - /**  
52 - * 判断 key 是否存在  
53 - * @param key 键  
54 - * @return true / false  
55 - */  
56 - public boolean hasKey(String key) {  
57 - try {  
58 - return redisTemplate.hasKey(key);  
59 - } catch (Exception e) {  
60 - e.printStackTrace();  
61 - return false;  
62 - }  
63 - }  
64 -  
65 - /**  
66 - * 删除缓存  
67 - * @SuppressWarnings("unchecked") 忽略类型转换警告  
68 - * @param key 键(一个或者多个)  
69 - */  
70 - public boolean del(String... key) {  
71 - try {  
72 - if (key != null && key.length > 0) {  
73 - if (key.length == 1) {  
74 - redisTemplate.delete(key[0]);  
75 - } else {  
76 -// 传入一个 Collection<String> 集合  
77 - redisTemplate.delete(CollectionUtils.arrayToList(key));  
78 - }  
79 - }  
80 - return true;  
81 - } catch (Exception e) {  
82 - e.printStackTrace();  
83 - return false;  
84 - }  
85 - }  
86 -  
87 -// ============================== String ==============================  
88 -  
89 - /**  
90 - * 普通缓存获取  
91 - * @param key 键  
92 - * @return 值  
93 - */  
94 - public Object get(String key) {  
95 - return key == null ? null : redisTemplate.opsForValue().get(key);  
96 - }  
97 -  
98 - /**  
99 - * 普通缓存放入  
100 - * @param key 键  
101 - * @param value 值  
102 - * @return true / false  
103 - */  
104 - public boolean set(String key, Object value) {  
105 - try {  
106 - redisTemplate.opsForValue().set(key, value);  
107 - return true;  
108 - } catch (Exception e) {  
109 -// e.printStackTrace();  
110 - return false;  
111 - }  
112 - }  
113 -  
114 - /**  
115 - * 普通缓存放入并设置时间  
116 - * @param key 键  
117 - * @param value 值  
118 - * @param time 时间(秒),如果 time < 0 则设置无限时间  
119 - * @return true / false  
120 - */  
121 - public boolean set(String key, Object value, long time) {  
122 - try {  
123 - if (time > 0) {  
124 - redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);  
125 - } else {  
126 - set(key, value);  
127 - }  
128 - return true;  
129 - } catch (Exception e) {  
130 - e.printStackTrace();  
131 - return false;  
132 - }  
133 - }  
134 -  
135 - /**  
136 - * 递增  
137 - * @param key 键  
138 - * @param delta 递增大小  
139 - * @return  
140 - */  
141 - public long incr(String key, long delta) {  
142 - if (delta < 0) {  
143 - throw new RuntimeException("递增因子必须大于 0");  
144 - }  
145 - return redisTemplate.opsForValue().increment(key, delta);  
146 - }  
147 -  
148 - /**  
149 - * 递减  
150 - * @param key 键  
151 - * @param delta 递减大小  
152 - * @return  
153 - */  
154 - public long decr(String key, long delta) {  
155 - if (delta < 0) {  
156 - throw new RuntimeException("递减因子必须大于 0");  
157 - }  
158 - return redisTemplate.opsForValue().increment(key, delta);  
159 - }  
160 -  
161 -// ============================== Map ==============================  
162 -  
163 - /**  
164 - * HashGet  
165 - * @param key 键(no null)  
166 - * @param item 项(no null)  
167 - * @return 值  
168 - */  
169 - public Object hget(String key, String item) {  
170 - return redisTemplate.opsForHash().get(key, item);  
171 - }  
172 -  
173 - /**  
174 - * 获取 key 对应的 map  
175 - * @param key 键(no null)  
176 - * @return 对应的多个键值  
177 - */  
178 - public Map<Object, Object> hmget(String key) {  
179 - return redisTemplate.opsForHash().entries(key);  
180 - }  
181 -  
182 - /**  
183 - * HashSet  
184 - * @param key 键  
185 - * @param map 值  
186 - * @return true / false  
187 - */  
188 - public boolean hmset(String key, Map<Object, Object> map) {  
189 - try {  
190 - redisTemplate.opsForHash().putAll(key, map);  
191 - return true;  
192 - } catch (Exception e) {  
193 - e.printStackTrace();  
194 - return false;  
195 - }  
196 - }  
197 -  
198 - /**  
199 - * HashSet 并设置时间  
200 - * @param key 键  
201 - * @param map 值  
202 - * @param time 时间  
203 - * @return true / false  
204 - */  
205 - public boolean hmset(String key, Map<Object, Object> map, long time) {  
206 - try {  
207 - redisTemplate.opsForHash().putAll(key, map);  
208 - if (time > 0) {  
209 - expire(key, time);  
210 - }  
211 - return true;  
212 - } catch (Exception e) {  
213 - e.printStackTrace();  
214 - return false;  
215 - }  
216 - }  
217 -  
218 - /**  
219 - * 向一张 Hash表 中放入数据,如不存在则创建  
220 - * @param key 键  
221 - * @param item 项  
222 - * @param value 值  
223 - * @return true / false  
224 - */  
225 - public boolean hset(String key, String item, Object value) {  
226 - try {  
227 - redisTemplate.opsForHash().put(key, item, value);  
228 - return true;  
229 - } catch (Exception e) {  
230 - e.printStackTrace();  
231 - return false;  
232 - }  
233 - }  
234 -  
235 - /**  
236 - * 向一张 Hash表 中放入数据,并设置时间,如不存在则创建  
237 - * @param key 键  
238 - * @param item 项  
239 - * @param value 值  
240 - * @param time 时间(如果原来的 Hash表 设置了时间,这里会覆盖)  
241 - * @return true / false  
242 - */  
243 - public boolean hset(String key, String item, Object value, long time) {  
244 - try {  
245 - redisTemplate.opsForHash().put(key, item, value);  
246 - if (time > 0) {  
247 - expire(key, time);  
248 - }  
249 - return true;  
250 - } catch (Exception e) {  
251 - e.printStackTrace();  
252 - return false;  
253 - }  
254 - }  
255 -  
256 - /**  
257 - * 删除 Hash表 中的值  
258 - * @param key 键  
259 - * @param item 项(可以多个,no null)  
260 - */  
261 - public void hdel(String key, Object... item) {  
262 - redisTemplate.opsForHash().delete(key, item);  
263 - }  
264 -  
265 - /**  
266 - * 判断 Hash表 中是否有该键的值  
267 - * @param key 键(no null)  
268 - * @param item 值(no null)  
269 - * @return true / false  
270 - */  
271 - public boolean hHasKey(String key, String item) {  
272 - return redisTemplate.opsForHash().hasKey(key, item);  
273 - }  
274 -  
275 - /**  
276 - * Hash递增,如果不存在则创建一个,并把新增的值返回  
277 - * @param key 键  
278 - * @param item 项  
279 - * @param by 递增大小 > 0  
280 - * @return  
281 - */  
282 - public Double hincr(String key, String item, Double by) {  
283 - return redisTemplate.opsForHash().increment(key, item, by);  
284 - }  
285 -  
286 - /**  
287 - * Hash递减  
288 - * @param key 键  
289 - * @param item 项  
290 - * @param by 递减大小  
291 - * @return  
292 - */  
293 - public Double hdecr(String key, String item, Double by) {  
294 - return redisTemplate.opsForHash().increment(key, item, -by);  
295 - }  
296 -  
297 -// ============================== Set ==============================  
298 -  
299 - /**  
300 - * 根据 key 获取 set 中的所有值  
301 - * @param key 键  
302 - * @return 值  
303 - */  
304 - public Set<Object> sGet(String key) {  
305 - try {  
306 - return redisTemplate.opsForSet().members(key);  
307 - } catch (Exception e) {  
308 - e.printStackTrace();  
309 - return null;  
310 - }  
311 - }  
312 -  
313 - /**  
314 - * 从键为 key 的 set 中,根据 value 查询是否存在  
315 - * @param key 键  
316 - * @param value 值  
317 - * @return true / false  
318 - */  
319 - public boolean sHasKey(String key, Object value) {  
320 - try {  
321 - return redisTemplate.opsForSet().isMember(key, value);  
322 - } catch (Exception e) {  
323 - e.printStackTrace();  
324 - return false;  
325 - }  
326 - }  
327 -  
328 - /**  
329 - * 将数据放入 set缓存  
330 - * @param key 键值  
331 - * @param values 值(可以多个)  
332 - * @return 成功个数  
333 - */  
334 - public long sSet(String key, Object... values) {  
335 - try {  
336 - return redisTemplate.opsForSet().add(key, values);  
337 - } catch (Exception e) {  
338 - e.printStackTrace();  
339 - return 0;  
340 - }  
341 - }  
342 -  
343 - /**  
344 - * 将数据放入 set缓存,并设置时间  
345 - * @param key 键  
346 - * @param time 时间  
347 - * @param values 值(可以多个)  
348 - * @return 成功放入个数  
349 - */  
350 - public long sSet(String key, long time, Object... values) {  
351 - try {  
352 - long count = redisTemplate.opsForSet().add(key, values);  
353 - if (time > 0) {  
354 - expire(key, time);  
355 - }  
356 - return count;  
357 - } catch (Exception e) {  
358 - e.printStackTrace();  
359 - return 0;  
360 - }  
361 - }  
362 -  
363 - /**  
364 - * 获取 set缓存的长度  
365 - * @param key 键  
366 - * @return 长度  
367 - */  
368 - public long sGetSetSize(String key) {  
369 - try {  
370 - return redisTemplate.opsForSet().size(key);  
371 - } catch (Exception e) {  
372 - e.printStackTrace();  
373 - return 0;  
374 - }  
375 - }  
376 -  
377 - /**  
378 - * 移除 set缓存中,值为 value 的  
379 - * @param key 键  
380 - * @param values 值  
381 - * @return 成功移除个数  
382 - */  
383 - public long setRemove(String key, Object... values) {  
384 - try {  
385 - return redisTemplate.opsForSet().remove(key, values);  
386 - } catch (Exception e) {  
387 - e.printStackTrace();  
388 - return 0;  
389 - }  
390 - }  
391 -// ============================== ZSet ==============================  
392 -  
393 - /**  
394 - * 添加一个元素, zset与set最大的区别就是每个元素都有一个score,因此有个排序的辅助功能; zadd  
395 - *  
396 - * @param key  
397 - * @param value  
398 - * @param score  
399 - */  
400 - public void zAdd(Object key, Object value, double score) {  
401 - redisTemplate.opsForZSet().add(key, value, score);  
402 - }  
403 -  
404 - /**  
405 - * 删除元素 zrem  
406 - *  
407 - * @param key  
408 - * @param value  
409 - */  
410 - public void zRemove(Object key, Object value) {  
411 - redisTemplate.opsForZSet().remove(key, value);  
412 - }  
413 -  
414 - /**  
415 - * score的增加or减少 zincrby  
416 - *  
417 - * @param key  
418 - * @param value  
419 - * @param score  
420 - */  
421 - public Double zIncrScore(Object key, Object value, double score) {  
422 - return redisTemplate.opsForZSet().incrementScore(key, value, score);  
423 - }  
424 -  
425 - /**  
426 - * 查询value对应的score zscore  
427 - *  
428 - * @param key  
429 - * @param value  
430 - * @return  
431 - */  
432 - public Double zScore(Object key, Object value) {  
433 - return redisTemplate.opsForZSet().score(key, value);  
434 - }  
435 -  
436 - /**  
437 - * 判断value在zset中的排名 zrank  
438 - *  
439 - * @param key  
440 - * @param value  
441 - * @return  
442 - */  
443 - public Long zRank(Object key, Object value) {  
444 - return redisTemplate.opsForZSet().rank(key, value);  
445 - }  
446 -  
447 - /**  
448 - * 返回集合的长度  
449 - *  
450 - * @param key  
451 - * @return  
452 - */  
453 - public Long zSize(Object key) {  
454 - return redisTemplate.opsForZSet().zCard(key);  
455 - }  
456 -  
457 - /**  
458 - * 查询集合中指定顺序的值, 0 -1 表示获取全部的集合内容 zrange  
459 - *  
460 - * 返回有序的集合,score小的在前面  
461 - *  
462 - * @param key  
463 - * @param start  
464 - * @param end  
465 - * @return  
466 - */  
467 - public Set<Object> ZRange(Object key, int start, int end) {  
468 - return redisTemplate.opsForZSet().range(key, start, end);  
469 - }  
470 - /**  
471 - * 查询集合中指定顺序的值和score,0, -1 表示获取全部的集合内容  
472 - *  
473 - * @param key  
474 - * @param start  
475 - * @param end  
476 - * @return  
477 - */  
478 - public Set<ZSetOperations.TypedTuple<Object>> zRangeWithScore(Object key, int start, int end) {  
479 - return redisTemplate.opsForZSet().rangeWithScores(key, start, end);  
480 - }  
481 - /**  
482 - * 查询集合中指定顺序的值 zrevrange  
483 - *  
484 - * 返回有序的集合中,score大的在前面  
485 - *  
486 - * @param key  
487 - * @param start  
488 - * @param end  
489 - * @return  
490 - */  
491 - public Set<Object> zRevRange(Object key, int start, int end) {  
492 - return redisTemplate.opsForZSet().reverseRange(key, start, end);  
493 - }  
494 - /**  
495 - * 根据score的值,来获取满足条件的集合 zrangebyscore  
496 - *  
497 - * @param key  
498 - * @param min  
499 - * @param max  
500 - * @return  
501 - */  
502 - public Set<Object> zSortRange(Object key, int min, int max) {  
503 - return redisTemplate.opsForZSet().rangeByScore(key, min, max);  
504 - }  
505 -  
506 -  
507 -// ============================== List ==============================  
508 -  
509 - /**  
510 - * 获取 list缓存的内容  
511 - * @param key 键  
512 - * @param start 开始  
513 - * @param end 结束(0 到 -1 代表所有值)  
514 - * @return  
515 - */  
516 - public List<Object> lGet(String key, long start, long end) {  
517 - try {  
518 - return redisTemplate.opsForList().range(key, start, end);  
519 - } catch (Exception e) {  
520 - e.printStackTrace();  
521 - return null;  
522 - }  
523 - }  
524 -  
525 - /**  
526 - * 获取 list缓存的长度  
527 - * @param key 键  
528 - * @return 长度  
529 - */  
530 - public long lGetListSize(String key) {  
531 - try {  
532 - return redisTemplate.opsForList().size(key);  
533 - } catch (Exception e) {  
534 - e.printStackTrace();  
535 - return 0;  
536 - }  
537 - }  
538 -  
539 - /**  
540 - * 根据索引 index 获取键为 key 的 list 中的元素  
541 - * @param key 键  
542 - * @param index 索引  
543 - * 当 index >= 0 时 {0:表头, 1:第二个元素}  
544 - * 当 index < 0 时 {-1:表尾, -2:倒数第二个元素}  
545 - * @return 值  
546 - */  
547 - public Object lGetIndex(String key, long index) {  
548 - try {  
549 - return redisTemplate.opsForList().index(key, index);  
550 - } catch (Exception e) {  
551 - e.printStackTrace();  
552 - return null;  
553 - }  
554 - }  
555 -  
556 - /**  
557 - * 将值 value 插入键为 key 的 list 中,如果 list 不存在则创建空 list  
558 - * @param key 键  
559 - * @param value 值  
560 - * @return true / false  
561 - */  
562 - public boolean lSet(String key, Object value) {  
563 - try {  
564 - redisTemplate.opsForList().rightPush(key, value);  
565 - return true;  
566 - } catch (Exception e) {  
567 - e.printStackTrace();  
568 - return false;  
569 - }  
570 - }  
571 -  
572 - /**  
573 - * 将值 value 插入键为 key 的 list 中,并设置时间  
574 - * @param key 键  
575 - * @param value 值  
576 - * @param time 时间  
577 - * @return true / false  
578 - */  
579 - public boolean lSet(String key, Object value, long time) {  
580 - try {  
581 - redisTemplate.opsForList().rightPush(key, value);  
582 - if (time > 0) {  
583 - expire(key, time);  
584 - }  
585 - return true;  
586 - } catch (Exception e) {  
587 - e.printStackTrace();  
588 - return false;  
589 - }  
590 - }  
591 -  
592 - /**  
593 - * 将 values 插入键为 key 的 list 中  
594 - * @param key 键  
595 - * @param values 值  
596 - * @return true / false  
597 - */  
598 - public boolean lSetList(String key, List<Object> values) {  
599 - try {  
600 - redisTemplate.opsForList().rightPushAll(key, values);  
601 - return true;  
602 - } catch (Exception e) {  
603 - e.printStackTrace();  
604 - return false;  
605 - }  
606 - }  
607 -  
608 - /**  
609 - * 将 values 插入键为 key 的 list 中,并设置时间  
610 - * @param key 键  
611 - * @param values 值  
612 - * @param time 时间  
613 - * @return true / false  
614 - */  
615 - public boolean lSetList(String key, List<Object> values, long time) {  
616 - try {  
617 - redisTemplate.opsForList().rightPushAll(key, values);  
618 - if (time > 0) {  
619 - expire(key, time);  
620 - }  
621 - return true;  
622 - } catch (Exception e) {  
623 - e.printStackTrace();  
624 - return false;  
625 - }  
626 - }  
627 -  
628 - /**  
629 - * 根据索引 index 修改键为 key 的值  
630 - * @param key 键  
631 - * @param index 索引  
632 - * @param value 值  
633 - * @return true / false  
634 - */  
635 - public boolean lUpdateIndex(String key, long index, Object value) {  
636 - try {  
637 - redisTemplate.opsForList().set(key, index, value);  
638 - return true;  
639 - } catch (Exception e) {  
640 - e.printStackTrace();  
641 - return false;  
642 - }  
643 - }  
644 -  
645 - /**  
646 - * 在键为 key 的 list 中删除值为 value 的元素  
647 - * @param key 键  
648 - * @param count 如果 count == 0 则删除 list 中所有值为 value 的元素  
649 - * 如果 count > 0 则删除 list 中最左边那个值为 value 的元素  
650 - * 如果 count < 0 则删除 list 中最右边那个值为 value 的元素  
651 - * @param value  
652 - * @return  
653 - */  
654 - public long lRemove(String key, long count, Object value) {  
655 - try {  
656 - return redisTemplate.opsForList().remove(key, count, value);  
657 - } catch (Exception e) {  
658 - e.printStackTrace();  
659 - return 0;  
660 - }  
661 - }  
662 -  
663 - /**  
664 - * 模糊查询  
665 - * @param key 键  
666 - * @return true / false  
667 - */  
668 - public List<Object> keys(String key) {  
669 - try {  
670 - Set<Object> set = redisTemplate.keys(key);  
671 - return new ArrayList<>(set);  
672 - } catch (Exception e) {  
673 - e.printStackTrace();  
674 - return null;  
675 - }  
676 - }  
677 -  
678 -  
679 - /**  
680 - * 模糊查询  
681 - * @param query 查询参数  
682 - * @return  
683 - */  
684 -// public List<Object> scan(String query) {  
685 -// List<Object> result = new ArrayList<>();  
686 -// try {  
687 -// Cursor<Map.Entry<Object,Object>> cursor = redisTemplate.opsForHash().scan("field",  
688 -// ScanOptions.scanOptions().match(query).count(1000).build());  
689 -// while (cursor.hasNext()) {  
690 -// Map.Entry<Object,Object> entry = cursor.next();  
691 -// result.add(entry.getKey());  
692 -// Object key = entry.getKey();  
693 -// Object valueSet = entry.getValue();  
694 -// }  
695 -// //关闭cursor  
696 -// cursor.close();  
697 -// } catch (Exception e) {  
698 -// e.printStackTrace();  
699 -// }  
700 -// return result;  
701 -// }  
702 -  
703 - /**  
704 - * 模糊查询  
705 - * @param query 查询参数  
706 - * @return  
707 - */  
708 - public List<Object> scan(String query) {  
709 - Set<String> resultKeys = redisTemplate.execute((RedisCallback<Set<String>>) connection -> {  
710 - ScanOptions scanOptions = ScanOptions.scanOptions().match("*" + query + "*").count(1000).build();  
711 - Cursor<byte[]> scan = connection.scan(scanOptions);  
712 - Set<String> keys = new HashSet<>();  
713 - while (scan.hasNext()) {  
714 - byte[] next = scan.next();  
715 - keys.add(new String(next));  
716 - }  
717 - return keys;  
718 - });  
719 -  
720 - return new ArrayList<>(resultKeys);  
721 - }  
722 -  
723 -}  
src/main/resources/all-application.yml deleted 100755 → 0
1 -spring:  
2 - # REDIS数据库配置  
3 - redis:  
4 - # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1  
5 - host: 127.0.0.1  
6 - # [必须修改] 端口号  
7 - port: 6379  
8 - # [可选] 数据库 DB  
9 - database: 8  
10 - # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接  
11 - password:  
12 - # [可选] 超时时间  
13 - timeout: 10000  
14 -  
15 -# [必选] WVP监听的HTTP端口, 网页和接口调用都是这个端口  
16 -server:  
17 - port: 18081  
18 - # [可选] HTTPS配置, 默认不开启  
19 - ssl:  
20 - # [可选] 是否开启HTTPS访问  
21 - enabled: false  
22 - # [可选] 证书文件路径,放置在resource/目录下即可,修改xxx为文件名  
23 - key-store: classpath:xxx.jks  
24 - # [可选] 证书密码  
25 - key-password: password  
26 - # [可选] 证书类型, 默认为jks,根据实际修改  
27 - key-store-type: JKS  
28 -  
29 -# [根据业务需求配置]  
30 -user-settings:  
31 - # [可选 ] zlm配置的录像路径,不配置则使用当前目录下的record目录 即: ./record  
32 - record: /media/lin/Server/ZLMediaKit/dev/ZLMediaKit/release/linux/Debug/www/record  
33 - # [可选 ] 录像保存时长(单位: 天)每天晚12点自动对过期文件执行清理, 不配置则不删除  
34 - recordDay: 7  
35 - # [可选 ] 录像下载合成临时文件保存时长, 不配置默认取值recordDay(单位: 天)每天晚12点自动对过期文件执行清理  
36 - # recordTempDay: 7  
37 - # [必选 ] ffmpeg路径  
38 - ffmpeg: /usr/bin/ffmpeg  
39 - # [必选 ] ffprobe路径, 一般安装ffmpeg就会自带, 一般跟ffmpeg在同一目录,用于查询文件的信息  
40 - ffprobe: /usr/bin/ffprobe  
41 - # [可选 ] 限制 ffmpeg 合并文件使用的线程数,间接限制cpu使用率, 默认2 限制到50%  
42 - threads: 2  
43 -  
44 -swagger-ui:  
45 -  
46 -# [可选] 日志配置, 一般不需要改  
47 -logging:  
48 - file:  
49 - name: logs/wvp.log  
50 - max-history: 30  
51 - max-size: 10MB  
52 - total-size-cap: 300MB  
53 - level:  
54 - root: WARN  
55 - top:  
56 - panll:  
57 - assist: info  
58 \ No newline at end of file 0 \ No newline at end of file
src/main/resources/application-dev.yml deleted 100755 → 0
1 -spring:  
2 - # REDIS数据库配置  
3 - redis:  
4 - # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1  
5 - host: 127.0.0.1  
6 - # [必须修改] 端口号  
7 - port: 6379  
8 - # [可选] 数据库 DB  
9 - database: 8  
10 - # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接  
11 - password:  
12 - # [可选] 超时时间  
13 - timeout: 10000  
14 -  
15 -# [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口  
16 -server:  
17 - port: 18081  
18 - # [可选] HTTPS配置, 默认不开启  
19 - ssl:  
20 - # [可选] 是否开启HTTPS访问  
21 - enabled: false  
22 - # [可选] 证书文件路径,放置在resource/目录下即可,修改xxx为文件名  
23 - key-store: classpath:xxx.jks  
24 - # [可选] 证书密码  
25 - key-password: password  
26 - # [可选] 证书类型, 默认为jks,根据实际修改  
27 - key-store-type: JKS  
28 -  
29 -# [根据业务需求配置]  
30 -userSettings:  
31 - # [可选 ] zlm配置的录像路径,  
32 - record: /media/lin/Server/ZLMediaKit/dev/ZLMediaKit/release/linux/Debug/www/record  
33 - # [可选 ] 录像保存时长(单位: 天)每天晚12点自动对过期文件执行清理  
34 - recordDay: 7  
35 - # [可选 ] 录像下载合成临时文件保存时长, 不配置默认取值recordDay(单位: 天)每天晚12点自动对过期文件执行清理  
36 - # recordTempDay: 7  
37 - # [必选 ] ffmpeg路径  
38 - ffmpeg: /usr/bin/ffmpeg  
39 - # [必选 ] ffprobe路径, 一般安装ffmpeg就会自带, 一般跟ffmpeg在同一目录,用于查询文件的信息  
40 - ffprobe: /usr/bin/ffprobe  
41 - # [可选 ] 限制 ffmpeg 合并文件使用的线程数,间接限制cpu使用率, 默认2 限制到50%  
42 - threads: 2  
43 -  
44 -swagger-ui:  
45 -  
46 -# [可选] 日志配置, 一般不需要改  
47 -logging:  
48 - file:  
49 - name: logs/wvp.log  
50 - max-history: 30  
51 - max-size: 10MB  
52 - total-size-cap: 300MB  
53 - level:  
54 - root: WARN  
55 - top:  
56 - panll:  
57 - assist: info  
58 \ No newline at end of file 0 \ No newline at end of file
src/main/resources/application-local.yml deleted 100755 → 0
1 -spring:  
2 - # REDIS数据库配置  
3 - redis:  
4 - # [可选] 超时时间  
5 - timeout: 10000  
6 - # 以下为单机配置  
7 - # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1  
8 - host: 127.0.0.1  
9 - # [必须修改] 端口号  
10 - port: 6379  
11 - # [可选] 数据库 DB  
12 - database: 1  
13 - # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接  
14 - password: adminadmin123.  
15 - # 以下为集群配置  
16 -# cluster:  
17 -# nodes: 192.168.1.242:7001  
18 -# password: 4767cb971b40a1300fa09b7f87b09d1c  
19 -  
20 -# [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口  
21 -server:  
22 - port: 18089  
23 - # [可选] HTTPS配置, 默认不开启  
24 - ssl:  
25 - # [可选] 是否开启HTTPS访问  
26 - enabled: false  
27 - # [可选] 证书文件路径,放置在resource/目录下即可,修改xxx为文件名  
28 - key-store: classpath:xxx.jks  
29 - # [可选] 证书密码  
30 - key-password: password  
31 - # [可选] 证书类型, 默认为jks,根据实际修改  
32 - key-store-type: JKS  
33 -  
34 -# [根据业务需求配置]  
35 -userSettings:  
36 - # [必选 ] 服务ID  
37 - id: 334533  
38 - # [必选 ] 录像路径  
39 - record: /home/lin/record/  
40 - # [可选 ] 录像保存时长(单位: 天)每天晚12点自动对过期文件执行清理  
41 - recordDay: 10  
42 - # [可选 ] 录像下载合成临时文件保存时长, 不配置默认取值recordDay(单位: 天)每天晚12点自动对过期文件执行清理  
43 - # recordTempDay: 7  
44 - # [必选 ] ffmpeg路径  
45 - ffmpeg: /home/lin/IdeaProjects/wvp-pro-assist/lib/ffmpeg  
46 - # [必选 ] ffprobe路径, 一般安装ffmpeg就会自带, 一般跟ffmpeg在同一目录,用于查询文件的信息,  
47 - ffprobe: /home/lin/IdeaProjects/wvp-pro-assist/lib/ffprobe  
48 - # [可选 ] 限制 ffmpeg 合并文件使用的线程数,间接限制cpu使用率, 默认2 限制到50%  
49 - threads: 2  
50 -  
51 -# [可选] 日志配置, 一般不需要改  
52 -logging:  
53 - file:  
54 - name: logs/wvp.log  
55 - max-history: 30  
56 - max-size: 10MB  
57 - total-size-cap: 300MB  
58 - level:  
59 - root: WARN  
60 - top:  
61 - panll:  
62 - assist: info  
63 \ No newline at end of file 0 \ No newline at end of file
src/main/resources/application.yml
1 spring: 1 spring:
2 - profiles:  
3 - active: local 2 + application:
  3 + name: wvp-assist
  4 + datasource:
  5 + type: com.zaxxer.hikari.HikariDataSource
  6 + driver-class-name: com.mysql.cj.jdbc.Driver
  7 + url: jdbc:mysql://127.0.0.1:3306/wvp_test?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true&allowPublicKeyRetrieval=true
  8 + username: root
  9 + password: 12345678
  10 +
  11 +# [必选] WVP监听的HTTP端口, 网页和接口调用都是这个端口
  12 +server:
  13 + port: 18081
  14 +
  15 +# [根据业务需求配置]
  16 +user-settings:
  17 + id: 1111
  18 + media-server-id: 11212
  19 + # [可选 ] zlm配置的录像路径,不配置则使用当前目录下的record目录 即: ./record
  20 + record: /home/lin/record/
  21 + # [可选 ] 录像保存时长(单位: 天)每天晚12点自动对过期文件执行清理, 不配置则不删除
  22 + recordDay: 7
  23 + # [可选 ] 录像下载合成临时文件保存时长, 不配置默认取值recordDay(单位: 天)每天晚12点自动对过期文件执行清理
  24 + # recordTempDay: 7
  25 + # [必选 ] ffmpeg路径
  26 + ffmpeg: /usr/bin/ffmpeg
  27 + # [必选 ] ffprobe路径, 一般安装ffmpeg就会自带, 一般跟ffmpeg在同一目录,用于查询文件的信息
  28 + ffprobe: /usr/bin/ffprobe
  29 + # [可选 ] 限制 ffmpeg 合并文件使用的线程数,间接限制cpu使用率, 默认2 限制到50%
  30 + threads: 2
  31 +
  32 +
  33 +# [可选] 日志配置, 一般不需要改
  34 +logging:
  35 + file:
  36 + name: logs/wvp.log
  37 + max-history: 30
  38 + max-size: 10MB
  39 + total-size-cap: 300MB
  40 + level:
  41 + root: WARN
  42 + top:
  43 + panll:
  44 + assist: info
4 \ No newline at end of file 45 \ No newline at end of file
src/main/resources/static/download.html deleted 100755 → 0
1 -<!DOCTYPE html>  
2 -<html lang="en">  
3 -<head>  
4 - <meta charset="UTF-8">  
5 - <meta http-equiv="X-UA-Compatible" content="IE=edge">  
6 - <meta name="viewport" content="width=device-width, initial-scale=1.0">  
7 - <title>下载</title>  
8 -</head>  
9 -<body>  
10 -<a id="download" download></a>  
11 -<script>  
12 - (function () {  
13 - let searchParams = new URLSearchParams(location.search);  
14 - var download = document.getElementById("download");  
15 - download.setAttribute("href", searchParams.get("url"))  
16 - download.click()  
17 - setTimeout(() => {  
18 - window.location.href = "about:blank";  
19 - window.close();  
20 - }, 200)  
21 - })();  
22 -  
23 -</script>  
24 -</body>  
25 -</html>  
26 \ No newline at end of file 0 \ No newline at end of file