wanghongbo

垫片上传、切换相关逻辑修改

@@ -51,6 +51,13 @@ public class BackupMaterialController { @@ -51,6 +51,13 @@ public class BackupMaterialController {
51 return backupMaterialService.getByRoom(roomId); 51 return backupMaterialService.getByRoom(roomId);
52 } 52 }
53 53
  54 + /**
  55 + * @description 修改审片间垫片配置
  56 + * @author W5669
  57 + * @date 2025/7/24
  58 + * @param backupChangeDto
  59 + * @return ResultBean
  60 + */
54 @PostMapping("change") 61 @PostMapping("change")
55 ResultBean change(@RequestBody BackupChangeDto backupChangeDto){ 62 ResultBean change(@RequestBody BackupChangeDto backupChangeDto){
56 return backupMaterialService.change(backupChangeDto); 63 return backupMaterialService.change(backupChangeDto);
@@ -18,5 +18,7 @@ public class BackupUploadVo { @@ -18,5 +18,7 @@ public class BackupUploadVo {
18 private Long roomId; 18 private Long roomId;
19 //1:垫片1,2:垫片2 19 //1:垫片1,2:垫片2
20 private Integer backupOrder; 20 private Integer backupOrder;
  21 + //垫片状态 0-默认 1-当前选中
  22 + private String backupStatus;
21 23
22 } 24 }
  1 +package com.wondertek.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.util.List;
  6 +
  7 +/**
  8 + * @Description: 切换频道源请求参数
  9 + * @DateTime: 2020/7/25 10:05
  10 + */
  11 +@Data
  12 +public class ChangeSourceParam {
  13 + private String taskId;
  14 + private List<SourceUrl> sourceUrls;
  15 + private String backupUrl;
  16 + /**
  17 + * 是否切当前任务使用的源至pri=0的源;
  18 + * true,如果当前任务使用非pri=0的源则切至pri=0的源【即:如果当前任务在垫片上则切至主源上】;
  19 + * false,不执行切换源操作;
  20 + * 默认false
  21 + */
  22 + private boolean switchMaster;
  23 +}
  1 +package com.wondertek.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class SourceUrl {
  7 + //输入源
  8 + private String sourceUrl;
  9 + //输入源优先级
  10 + private int pri;
  11 +
  12 +}
@@ -2,35 +2,40 @@ package com.wondertek.service.impl; @@ -2,35 +2,40 @@ package com.wondertek.service.impl;
2 2
3 import cn.hutool.core.collection.CollectionUtil; 3 import cn.hutool.core.collection.CollectionUtil;
4 import cn.hutool.core.util.ObjectUtil; 4 import cn.hutool.core.util.ObjectUtil;
  5 +import cn.hutool.http.HttpRequest;
  6 +import cn.hutool.http.HttpResponse;
5 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 7 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
6 import com.baomidou.mybatisplus.core.metadata.IPage; 8 import com.baomidou.mybatisplus.core.metadata.IPage;
7 import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 9 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
8 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 10 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
9 -import com.wondertek.dto.BackupChangeDto;  
10 -import com.wondertek.dto.BackupMaterialDto;  
11 -import com.wondertek.dto.BackupUploadVo; 11 +import com.fasterxml.jackson.core.type.TypeReference;
  12 +import com.wondertek.dto.*;
12 import com.wondertek.entity.BackupConfig; 13 import com.wondertek.entity.BackupConfig;
13 import com.wondertek.entity.BackupMaterial; 14 import com.wondertek.entity.BackupMaterial;
14 import com.wondertek.entity.StreamTask; 15 import com.wondertek.entity.StreamTask;
  16 +import com.wondertek.enums.PlayTypeEnum;
15 import com.wondertek.exception.BusinessException; 17 import com.wondertek.exception.BusinessException;
16 import com.wondertek.mapper.BackupConfigMapper; 18 import com.wondertek.mapper.BackupConfigMapper;
17 import com.wondertek.mapper.BackupMaterialMapper; 19 import com.wondertek.mapper.BackupMaterialMapper;
  20 +import com.wondertek.mapper.StreamTaskMapper;
18 import com.wondertek.service.BackupMaterialService; 21 import com.wondertek.service.BackupMaterialService;
19 import com.wondertek.service.FileService; 22 import com.wondertek.service.FileService;
20 -import com.wondertek.util.FileUtils;  
21 -import com.wondertek.util.PageBean;  
22 -import com.wondertek.util.ResultBean;  
23 -import com.wondertek.util.UUIDUtil; 23 +import com.wondertek.util.*;
24 import jakarta.annotation.Resource; 24 import jakarta.annotation.Resource;
  25 +import lombok.extern.slf4j.Slf4j;
25 import org.apache.commons.lang3.StringUtils; 26 import org.apache.commons.lang3.StringUtils;
26 import org.springframework.beans.factory.annotation.Value; 27 import org.springframework.beans.factory.annotation.Value;
27 import org.springframework.stereotype.Service; 28 import org.springframework.stereotype.Service;
28 import org.springframework.web.multipart.MultipartFile; 29 import org.springframework.web.multipart.MultipartFile;
29 30
30 import java.time.LocalDateTime; 31 import java.time.LocalDateTime;
  32 +import java.util.Arrays;
  33 +import java.util.HashMap;
31 import java.util.List; 34 import java.util.List;
  35 +import java.util.Map;
32 36
33 @Service 37 @Service
  38 +@Slf4j
34 public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper, BackupMaterial> implements BackupMaterialService { 39 public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper, BackupMaterial> implements BackupMaterialService {
35 40
36 @Resource 41 @Resource
@@ -41,6 +46,12 @@ public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper, @@ -41,6 +46,12 @@ public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper,
41 private String realPath; 46 private String realPath;
42 @Resource 47 @Resource
43 private BackupConfigMapper backupConfigMapper; 48 private BackupConfigMapper backupConfigMapper;
  49 + @Resource
  50 + private StreamTaskMapper streamTaskMapper;
  51 + @Value("${transcode.switchStreamUrl}")
  52 + private String switchStreamUrl;
  53 + @Value("${transcode.swapBackupUrl}")
  54 + private String swapBackupUrl;
44 55
45 56
46 @Override 57 @Override
@@ -66,22 +77,30 @@ public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper, @@ -66,22 +77,30 @@ public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper,
66 77
67 @Override 78 @Override
68 public ResultBean upload(MultipartFile backupFile, BackupUploadVo backupUploadVo) { 79 public ResultBean upload(MultipartFile backupFile, BackupUploadVo backupUploadVo) {
69 - //上传文件 80 + //校验
70 if(!"mp4".equalsIgnoreCase(backupUploadVo.getFileType())){ 81 if(!"mp4".equalsIgnoreCase(backupUploadVo.getFileType())){
71 throw new BusinessException("仅支持上传mp4格式的垫片文件!"); 82 throw new BusinessException("仅支持上传mp4格式的垫片文件!");
72 } 83 }
73 - 84 + //对应垫片任务
  85 + LambdaQueryWrapper<StreamTask> backupWrapper = new LambdaQueryWrapper<>();
  86 + backupWrapper.eq(StreamTask::getRoomId,backupUploadVo.getRoomId());
  87 + String palyType = backupUploadVo.getBackupOrder() == 1? PlayTypeEnum.BACKUP1.getCode() : PlayTypeEnum.BACKUP2.getCode();
  88 + backupWrapper.eq(StreamTask::getPlayType,palyType);
  89 + StreamTask streamTask = streamTaskMapper.selectOne(backupWrapper);
  90 + if (streamTask == null){
  91 + return ResultBean.error("未找到该直播间对应的垫片任务");
  92 + }
  93 + //文件上传
74 String fileId = UUIDUtil.randomUUID(); 94 String fileId = UUIDUtil.randomUUID();
75 String fileName = backupUploadVo.getBackupName() + "." + backupUploadVo.getFileType(); 95 String fileName = backupUploadVo.getBackupName() + "." + backupUploadVo.getFileType();
76 ///home/wondertek/material_file_assets/dianpian/2025/07/24/roomid/ 96 ///home/wondertek/material_file_assets/dianpian/2025/07/24/roomid/
77 String filedir = FileUtils.generateDianPianDir(backupUploadVo.getRoomId().toString(), realPath); 97 String filedir = FileUtils.generateDianPianDir(backupUploadVo.getRoomId().toString(), realPath);
78 - String destFilePath = filedir + fileName;//文件上传目录 98 + String destFilePath = filedir + fileName;//文件上传目录,绝对路径
79 try { 99 try {
80 fileService.upload(backupFile, destFilePath); 100 fileService.upload(backupFile, destFilePath);
81 } catch (Exception e) { 101 } catch (Exception e) {
82 return ResultBean.error("上传文件异常"); 102 return ResultBean.error("上传文件异常");
83 } 103 }
84 -  
85 //保存垫片素材表 104 //保存垫片素材表
86 BackupMaterial backupMaterial = new BackupMaterial(); 105 BackupMaterial backupMaterial = new BackupMaterial();
87 backupMaterial.setFileId(fileId); 106 backupMaterial.setFileId(fileId);
@@ -103,21 +122,85 @@ public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper, @@ -103,21 +122,85 @@ public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper,
103 backupConfig.setRoomId(backupUploadVo.getRoomId()); 122 backupConfig.setRoomId(backupUploadVo.getRoomId());
104 backupConfig.setBackupId(backupMaterial.getId()); 123 backupConfig.setBackupId(backupMaterial.getId());
105 backupConfig.setBackupOrder(backupUploadVo.getBackupOrder()); 124 backupConfig.setBackupOrder(backupUploadVo.getBackupOrder());
  125 + backupConfig.setBackupStatus(backupUploadVo.getBackupStatus());
106 backupConfigMapper.insertOrUpdate(backupConfig); 126 backupConfigMapper.insertOrUpdate(backupConfig);
107 127
108 - //对应垫片任务切源(转码平台演示环境已挂载统一存储)  
109 - LambdaQueryWrapper<StreamTask> wrapper1 = new LambdaQueryWrapper<>();  
110 - wrapper1.eq(StreamTask::getRoomId,backupUploadVo.getRoomId());  
111 - wrapper1.eq(StreamTask::getPlayType,"play");  
112 -  
113 -  
114 -  
115 - 128 + //对应垫片任务切源(转码平台演示环境已挂载统一存储),请求转码平台修改垫片任务直播源
  129 + changeChannelSource(streamTask.getTaskId(), destFilePath);
116 //判断是否需要修改当前播出流的垫片 130 //判断是否需要修改当前播出流的垫片
  131 + if("1".equals(backupConfig.getBackupOrder())){
  132 + //切换播出流垫片(主、备)
  133 + LambdaQueryWrapper<StreamTask> playWrapper = new LambdaQueryWrapper<>();
  134 + playWrapper.eq(StreamTask::getRoomId,backupUploadVo.getRoomId());
  135 + playWrapper.eq(StreamTask::getPlayType,"play");
  136 + List<StreamTask> playTasks = streamTaskMapper.selectList(playWrapper);
  137 + if(CollectionUtil.isNotEmpty(playTasks)){
  138 + playTasks.forEach(playTask -> {
  139 + changeChannelSource(playTask.getTaskId(), destFilePath);
  140 + });
  141 + }
  142 + }
117 143
118 return ResultBean.ok("上传成功"); 144 return ResultBean.ok("上传成功");
119 } 145 }
120 146
  147 + private void changeBackup(String taskId, String destFilePath) {
  148 + Map<String, Object> paramsMap = new HashMap<>();
  149 + paramsMap.put("taskId", taskId);
  150 + paramsMap.put("backupUrl", destFilePath);
  151 + HttpResponse execute = null;
  152 + try {
  153 + execute = HttpRequest.post(swapBackupUrl)
  154 + .header("Content-Type", "application/json")
  155 + .body(JSONUtils.obj2json(paramsMap)).timeout(30000).execute();
  156 + if (execute.isOk()) {
  157 + log.info("-->请求转码系统换垫片接口,url:{},paramsMap:{}",swapBackupUrl,paramsMap);
  158 + String body = execute.body();
  159 + ResponseData response = JSONUtils.jsonToObject(body, new TypeReference<ResponseData>() {
  160 + });
  161 + if (response.getResultCode().equals("0")) {
  162 + log.info("请求转码系统换垫片接口成功");
  163 + }else {
  164 + log.info("请求转码系统换垫片接口响应失败,response:{}",response);
  165 + }
  166 + } else {
  167 + log.error("请求转码系统换垫片接口失败,url:{},body:{}", swapBackupUrl, execute.body());
  168 + }
  169 + } catch (Exception e) {
  170 + log.error("请求转码系统换垫片接口失败,url:{}", swapBackupUrl, e);
  171 + }
  172 + }
  173 +
  174 + private void changeChannelSource(String taskId, String destFilePath) {
  175 + ChangeSourceParam param = new ChangeSourceParam();
  176 + param.setTaskId(taskId);
  177 + SourceUrl sourceUrl = new SourceUrl();
  178 + sourceUrl.setSourceUrl(destFilePath);
  179 + sourceUrl.setPri(0);
  180 + param.setSourceUrls(Arrays.asList(sourceUrl));
  181 + HttpResponse execute = null;
  182 + try {
  183 + execute = HttpRequest.post(switchStreamUrl)
  184 + .header("Content-Type", "application/json")
  185 + .body(JSONUtils.obj2json(param)).timeout(30000).execute();
  186 + if (execute.isOk()) {
  187 + log.info("-->请求转码系统切换直播源接口,url:{},paramsMap:{}",switchStreamUrl,param);
  188 + String body = execute.body();
  189 + ResponseData response = JSONUtils.jsonToObject(body, new TypeReference<ResponseData>() {
  190 + });
  191 + if (response.getResultCode().equals("0")) {
  192 + log.info("请求转码系统切换直播源接口成功");
  193 + }else {
  194 + log.info("请求转码系统切换直播源接口响应失败,response:{}",response);
  195 + }
  196 + } else {
  197 + log.error("请求转码系统切换直播源接口失败,url:{},body:{}", switchStreamUrl, execute.body());
  198 + }
  199 + } catch (Exception e) {
  200 + log.error("请求转码系统切换直播源接口失败,url:{}", switchStreamUrl, e);
  201 + }
  202 + }
  203 +
121 @Override 204 @Override
122 public ResultBean getByRoom(Long roomId) { 205 public ResultBean getByRoom(Long roomId) {
123 LambdaQueryWrapper<BackupConfig> wrapper = new LambdaQueryWrapper<>(); 206 LambdaQueryWrapper<BackupConfig> wrapper = new LambdaQueryWrapper<>();
@@ -135,8 +218,19 @@ public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper, @@ -135,8 +218,19 @@ public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper,
135 backupConfigs.forEach(backupConfig -> { 218 backupConfigs.forEach(backupConfig -> {
136 if(backupConfig.getBackupId().equals(backupChangeDto.getBackupId())){ 219 if(backupConfig.getBackupId().equals(backupChangeDto.getBackupId())){
137 backupConfig.setBackupStatus("1"); 220 backupConfig.setBackupStatus("1");
138 - //将播放流的垫片配置切到此垫片上 221 + //将播放流的垫片配置切到此垫片上,播放流主、备都切换
  222 + LambdaQueryWrapper<StreamTask> playWrapper = new LambdaQueryWrapper<>();
  223 + playWrapper.eq(StreamTask::getRoomId,backupChangeDto.getRoomId());
  224 + playWrapper.eq(StreamTask::getPlayType,"play");
  225 + List<StreamTask> playTasks = streamTaskMapper.selectList(playWrapper);
  226 + if(CollectionUtil.isNotEmpty(playTasks)){
  227 + String backupPath = realPath + backupConfig.getBackupPath();
  228 + playTasks.forEach(playTask -> {
  229 + changeChannelSource(playTask.getTaskId(), backupPath);
  230 + });
  231 + }
139 }else { 232 }else {
  233 + //将其他垫片配置切到默认状态
140 backupConfig.setBackupStatus("0"); 234 backupConfig.setBackupStatus("0");
141 } 235 }
142 backupConfigMapper.updateById(backupConfig); 236 backupConfigMapper.updateById(backupConfig);
@@ -62,8 +62,13 @@ mybatis-plus: @@ -62,8 +62,13 @@ mybatis-plus:
62 transcode: 62 transcode:
63 delayTimeUrl: http://192.168.1.237:9002/api/v1/delayTime # 延迟接口 63 delayTimeUrl: http://192.168.1.237:9002/api/v1/delayTime # 延迟接口
64 blockStatusUrl: http://192.168.1.237:9002/api/v1/blockStatus # 屏蔽/恢复 64 blockStatusUrl: http://192.168.1.237:9002/api/v1/blockStatus # 屏蔽/恢复
  65 + switchStreamUrl: http://192.168.1.237:9002/api/v1/switchStream # 切换频道源
  66 + swapBackupUrl: http://192.168.1.237:9002/api/v1/swapBackup # 切垫片
65 getTaskDetail: http://192.168.1.237:9002/api/v1/getTaskDetail 67 getTaskDetail: http://192.168.1.237:9002/api/v1/getTaskDetail
66 68
  69 +file:
  70 + realPath: /home/wondertek/material_file_assets/
  71 +
67 crp: 72 crp:
68 user: 73 user:
69 username: admin 74 username: admin