修改vlog视频后台管理
This commit is contained in:
parent
2d0e662109
commit
62ce570195
@ -29,7 +29,11 @@
|
||||
<artifactId>minio</artifactId>
|
||||
<version>8.2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>3.14.9</version>
|
||||
</dependency>
|
||||
<!--腾讯云短信-->
|
||||
<dependency>
|
||||
<groupId>com.tencentcloudapi</groupId>
|
||||
@ -158,6 +162,26 @@
|
||||
<artifactId>spring-rabbit</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 腾讯云视频点播SDK -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.tencentcloudapi</groupId>-->
|
||||
<!-- <artifactId>tencentcloud-sdk-java-vod</artifactId>-->
|
||||
<!-- <version>3.1.1030</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!-- <!– 腾讯云SDK公共模块 –>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.tencentcloudapi</groupId>-->
|
||||
<!-- <artifactId>tencentcloud-sdk-java-common</artifactId>-->
|
||||
<!-- <version>3.1.1030</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!-- <!– 腾讯云SDK模型模块 –>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.tencentcloudapi</groupId>-->
|
||||
<!-- <artifactId>tencentcloud-sdk-java-models</artifactId>-->
|
||||
<!-- <version>3.1.1030</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -0,0 +1,201 @@
|
||||
package com.wzj.soopin.content.controller.admin;
|
||||
|
||||
import com.tencentcloudapi.vod.v20180717.models.*;
|
||||
import com.wzj.soopin.content.result.GraceJSONResult;
|
||||
import com.wzj.soopin.content.service.VlogUploadService;
|
||||
import com.wzj.soopin.content.utils.TencentCloudUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
|
||||
|
||||
@Slf4j
|
||||
@Api(tags = "管理端-视频上传接口")
|
||||
@RequestMapping("admin/vlog/upload")
|
||||
@RestController
|
||||
public class VlogUploadController {
|
||||
|
||||
@Autowired
|
||||
private VlogUploadService vlogUploadService;
|
||||
|
||||
@Autowired
|
||||
private TencentCloudUtil tencentCloudUtil;
|
||||
|
||||
@ApiOperation("获取腾讯云点播视频列表")
|
||||
@GetMapping("/list")
|
||||
public GraceJSONResult getVodList(
|
||||
@ApiParam(value = "页码", defaultValue = "1") @RequestParam(required = false, defaultValue = "1") Integer pageNum,
|
||||
@ApiParam(value = "每页记录数", defaultValue = "20") @RequestParam(required = false, defaultValue = "20") Integer pageSize,
|
||||
@ApiParam(value = "文件状态,可选值:Normal(正常)、SystemForbidden(平台封禁)、Forbidden(主动封禁)") @RequestParam(required = false) String[] status,
|
||||
@ApiParam(value = "文件类型,可选值:Video(视频)、Audio(音频)、Image(图片)") @RequestParam(required = false) String[] categories,
|
||||
@ApiParam(value = "媒体文件来源,可选值:Upload(上传)、Record(直播录制)等") @RequestParam(required = false) String[] sourceTypes,
|
||||
@ApiParam(value = "媒体文件封装格式,如:mp4、mov等") @RequestParam(required = false) String[] mediaTypes,
|
||||
@ApiParam(value = "文件名,支持模糊搜索") @RequestParam(required = false) String[] names,
|
||||
@ApiParam(value = "文件名前缀") @RequestParam(required = false) String[] namePrefixes,
|
||||
@ApiParam(value = "文件描述,支持模糊搜索") @RequestParam(required = false) String[] descriptions,
|
||||
@ApiParam(value = "标签") @RequestParam(required = false) String[] tags,
|
||||
@ApiParam(value = "分类ID") @RequestParam(required = false) Long[] classIds,
|
||||
@ApiParam(value = "存储地区,如:ap-guangzhou") @RequestParam(required = false) String[] storageRegions,
|
||||
@ApiParam(value = "创建时间范围-开始时间,格式:yyyy-MM-dd'T'HH:mm:ss'Z'") @RequestParam(required = false) String createTimeAfter,
|
||||
@ApiParam(value = "创建时间范围-结束时间,格式:yyyy-MM-dd'T'HH:mm:ss'Z'") @RequestParam(required = false) String createTimeBefore,
|
||||
@ApiParam(value = "排序字段,目前仅支持:CreateTime") @RequestParam(required = false, defaultValue = "CreateTime") String sortField,
|
||||
@ApiParam(value = "排序方式,可选值:Desc(降序)、Asc(升序)") @RequestParam(required = false, defaultValue = "Desc") String sortOrder,
|
||||
@ApiParam(value = "需要返回的信息类型,可选值:basicInfo(基础信息)、metaData(元信息)、transcodeInfo(转码信息)等") @RequestParam(required = false) String[] filters) {
|
||||
try {
|
||||
// 验证密钥配置
|
||||
String secretId = tencentCloudUtil.getSecretId();
|
||||
String secretKey = tencentCloudUtil.getSecretKey();
|
||||
if (secretId == null || secretId.isEmpty() || secretKey == null || secretKey.isEmpty()) {
|
||||
log.error("腾讯云密钥未配置");
|
||||
return GraceJSONResult.errorMsg("腾讯云密钥未配置");
|
||||
}
|
||||
|
||||
// 创建请求对象
|
||||
SearchMediaRequest req = new SearchMediaRequest();
|
||||
|
||||
// 设置分页参数
|
||||
req.setOffset((long) ((pageNum - 1) * pageSize));
|
||||
req.setLimit((long) pageSize);
|
||||
|
||||
// 设置排序
|
||||
SortBy sort = new SortBy();
|
||||
sort.setField(sortField);
|
||||
sort.setOrder(sortOrder);
|
||||
req.setSort(sort);
|
||||
|
||||
// 设置过滤条件
|
||||
if (categories != null && categories.length > 0) {
|
||||
req.setCategories(categories);
|
||||
}
|
||||
if (sourceTypes != null && sourceTypes.length > 0) {
|
||||
req.setSourceTypes(sourceTypes);
|
||||
}
|
||||
// if (mediaTypes != null && mediaTypes.length > 0) {
|
||||
// req.setMediaTypes(mediaTypes);
|
||||
// }
|
||||
if (names != null && names.length > 0) {
|
||||
req.setNames(names);
|
||||
}
|
||||
if (namePrefixes != null && namePrefixes.length > 0) {
|
||||
req.setNamePrefixes(namePrefixes);
|
||||
}
|
||||
if (descriptions != null && descriptions.length > 0) {
|
||||
req.setDescriptions(descriptions);
|
||||
}
|
||||
if (tags != null && tags.length > 0) {
|
||||
req.setTags(tags);
|
||||
}
|
||||
if (classIds != null && classIds.length > 0) {
|
||||
req.setClassIds(classIds);
|
||||
}
|
||||
if (storageRegions != null && storageRegions.length > 0) {
|
||||
req.setStorageRegions(storageRegions);
|
||||
}
|
||||
// if (createTimeAfter != null && !createTimeAfter.isEmpty()) {
|
||||
// req.setCreateTimeAfter(createTimeAfter);
|
||||
// }
|
||||
// if (createTimeBefore != null && !createTimeBefore.isEmpty()) {
|
||||
// req.setCreateTimeBefore(createTimeBefore);
|
||||
// }
|
||||
if (filters != null && filters.length > 0) {
|
||||
req.setFilters(filters);
|
||||
}
|
||||
|
||||
// 调用腾讯云API获取视频列表
|
||||
log.info("开始调用腾讯云 SearchMedia API");
|
||||
SearchMediaResponse resp = vlogUploadService.searchMedia(req);
|
||||
log.info("腾讯云 SearchMedia API 调用成功");
|
||||
|
||||
// 处理响应结果
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("totalCount", resp.getTotalCount());
|
||||
result.put("pageNum", pageNum);
|
||||
result.put("pageSize", pageSize);
|
||||
|
||||
List<Map<String, Object>> mediaList = new ArrayList<>();
|
||||
if (resp.getMediaInfoSet() != null) {
|
||||
for (MediaInfo mediaInfo : resp.getMediaInfoSet()) {
|
||||
Map<String, Object> mediaMap = new HashMap<>();
|
||||
// 基础信息
|
||||
MediaBasicInfo basicInfo = mediaInfo.getBasicInfo();
|
||||
mediaMap.put("fileId", mediaInfo.getFileId());
|
||||
mediaMap.put("name", basicInfo.getName());
|
||||
mediaMap.put("description", basicInfo.getDescription());
|
||||
mediaMap.put("createTime", basicInfo.getCreateTime());
|
||||
mediaMap.put("updateTime", basicInfo.getUpdateTime());
|
||||
mediaMap.put("expireTime", basicInfo.getExpireTime());
|
||||
mediaMap.put("classId", basicInfo.getClassId());
|
||||
mediaMap.put("className", basicInfo.getClassName());
|
||||
mediaMap.put("classPath", basicInfo.getClassPath());
|
||||
mediaMap.put("coverUrl", basicInfo.getCoverUrl());
|
||||
mediaMap.put("type", basicInfo.getType());
|
||||
mediaMap.put("mediaUrl", basicInfo.getMediaUrl());
|
||||
mediaMap.put("status", basicInfo.getStatus());
|
||||
mediaMap.put("storageRegion", basicInfo.getStorageRegion());
|
||||
mediaMap.put("category", basicInfo.getCategory());
|
||||
mediaMap.put("storageClass", basicInfo.getStorageClass());
|
||||
mediaMap.put("tagSet", basicInfo.getTagSet());
|
||||
mediaList.add(mediaMap);
|
||||
}
|
||||
}
|
||||
result.put("list", mediaList);
|
||||
|
||||
return GraceJSONResult.ok(result);
|
||||
} catch (Exception e) {
|
||||
log.error("获取视频列表失败", e);
|
||||
return GraceJSONResult.errorMsg("获取视频列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频审核接口
|
||||
*/
|
||||
@PostMapping("/audit")
|
||||
public GraceJSONResult auditVlog(@RequestParam String vlogId,
|
||||
@RequestParam Integer status,
|
||||
@RequestParam(required = false) String reason) {
|
||||
try {
|
||||
vlogUploadService.auditVlog(vlogId, status, reason);
|
||||
return GraceJSONResult.ok();
|
||||
} catch (Exception e) {
|
||||
log.error("视频审核失败", e);
|
||||
return GraceJSONResult.errorMsg("视频审核失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频删除接口
|
||||
*/
|
||||
@PostMapping("/delete")
|
||||
public GraceJSONResult deleteVlog(@RequestParam String vlogId) {
|
||||
try {
|
||||
vlogUploadService.deleteVlog(vlogId);
|
||||
return GraceJSONResult.ok();
|
||||
} catch (Exception e) {
|
||||
log.error("视频删除失败", e);
|
||||
return GraceJSONResult.errorMsg("视频删除失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频详情接口
|
||||
*/
|
||||
@GetMapping("/detail")
|
||||
public GraceJSONResult vlogDetail(@RequestParam String vlogId) {
|
||||
try {
|
||||
return GraceJSONResult.ok(vlogUploadService.getVlogDetail(vlogId));
|
||||
} catch (Exception e) {
|
||||
log.error("获取视频详情失败", e);
|
||||
return GraceJSONResult.errorMsg("获取视频详情失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.wzj.soopin.content.service;
|
||||
|
||||
import com.tencentcloudapi.vod.v20180717.models.PullUploadRequest;
|
||||
import com.tencentcloudapi.vod.v20180717.models.PullUploadResponse;
|
||||
import com.tencentcloudapi.vod.v20180717.models.SearchMediaRequest;
|
||||
import com.tencentcloudapi.vod.v20180717.models.SearchMediaResponse;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface VlogUploadService {
|
||||
|
||||
// /**
|
||||
// * 拉取视频上传
|
||||
// *
|
||||
// * @param req 拉取上传请求参数
|
||||
// * @return 拉取上传响应
|
||||
// */
|
||||
// PullUploadResponse pullUpload(PullUploadRequest req) throws Exception;
|
||||
//
|
||||
// /**
|
||||
// * 获取视频上传任务状态
|
||||
// *
|
||||
// * @param taskId 任务ID
|
||||
// * @return 任务状态信息
|
||||
// */
|
||||
// Map<String, Object> getTaskStatus(String taskId) throws Exception;
|
||||
|
||||
/**
|
||||
* 搜索媒体文件
|
||||
*
|
||||
* @param req 搜索请求
|
||||
* @return 搜索响应
|
||||
*/
|
||||
SearchMediaResponse searchMedia(SearchMediaRequest req);
|
||||
|
||||
// 新增:视频审核
|
||||
void auditVlog(String vlogId, Integer status, String reason);
|
||||
// 新增:视频删除
|
||||
void deleteVlog(String vlogId);
|
||||
// 新增:视频详情
|
||||
Object getVlogDetail(String vlogId);
|
||||
}
|
@ -0,0 +1,243 @@
|
||||
package com.wzj.soopin.content.service.impl;
|
||||
|
||||
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
|
||||
import com.tencentcloudapi.vod.v20180717.VodClient;
|
||||
import com.tencentcloudapi.vod.v20180717.models.DescribeTaskDetailRequest;
|
||||
import com.tencentcloudapi.vod.v20180717.models.DescribeTaskDetailResponse;
|
||||
import com.tencentcloudapi.vod.v20180717.models.PullUploadRequest;
|
||||
import com.tencentcloudapi.vod.v20180717.models.PullUploadResponse;
|
||||
import com.tencentcloudapi.vod.v20180717.models.SearchMediaRequest;
|
||||
import com.tencentcloudapi.vod.v20180717.models.SearchMediaResponse;
|
||||
import com.wzj.soopin.content.domain.vo.CommentVO;
|
||||
import com.wzj.soopin.content.service.VlogUploadService;
|
||||
import com.wzj.soopin.content.utils.TencentCloudUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class VlogUploadServiceImpl implements VlogUploadService {
|
||||
|
||||
@Autowired
|
||||
private TencentCloudUtil tencentCloudUtil;
|
||||
|
||||
@Autowired
|
||||
private com.wzj.soopin.content.mapper.VlogMapper vlogMapper;
|
||||
@Autowired
|
||||
private com.wzj.soopin.content.service.CommentService commentService;
|
||||
@Autowired
|
||||
private com.wzj.soopin.content.utils.RedisOperator redis;
|
||||
@Autowired
|
||||
private com.wzj.soopin.content.mapper.VlogMapperCustom vlogMapperCustom;
|
||||
|
||||
// @Override
|
||||
// public PullUploadResponse pullUpload(PullUploadRequest req) throws Exception {
|
||||
// // 获取VOD客户端实例
|
||||
// VodClient client = tencentCloudUtil.getVodClient();
|
||||
// // 返回的resp是一个PullUploadResponse的实例,与请求对象对应
|
||||
// return client.PullUpload(req);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public SearchMediaResponse searchMedia(SearchMediaRequest req) {
|
||||
try {
|
||||
// 获取VOD客户端实例
|
||||
VodClient client = tencentCloudUtil.getVodClient();
|
||||
|
||||
// 设置默认值
|
||||
if (req.getOffset() == null) {
|
||||
req.setOffset(0L);
|
||||
}
|
||||
if (req.getLimit() == null) {
|
||||
req.setLimit(10L);
|
||||
}
|
||||
|
||||
// 添加日志,打印请求参数
|
||||
// log.info("SearchMediaRequest 请求参数: {}", req.toJsonString());
|
||||
|
||||
// 添加调试信息
|
||||
log.info("请求时间戳: {}", System.currentTimeMillis());
|
||||
log.info("请求参数详情 - Offset: {}, Limit: {}, Sort: {}, Filters: {}",
|
||||
req.getOffset(),
|
||||
req.getLimit(),
|
||||
// req.getSort() != null ? req.getSort().toJsonString() : "null",
|
||||
req.getFilters() != null ? String.join(",", req.getFilters()) : "null");
|
||||
|
||||
// 验证请求参数
|
||||
validateSearchRequest(req);
|
||||
|
||||
SearchMediaResponse response = client.SearchMedia(req);
|
||||
log.info("SearchMedia API 调用成功,返回结果数: {}", response.getTotalCount());
|
||||
return response;
|
||||
} catch (TencentCloudSDKException e) {
|
||||
log.error("搜索媒体文件失败: {}", e.getMessage(), e);
|
||||
// 添加更详细的错误信息
|
||||
if (e.getMessage().contains("signature")) {
|
||||
log.error("签名验证失败,请检查:\n1. 密钥是否正确\n2. 服务器时间是否准确\n3. 时区设置是否正确");
|
||||
} else if (e.getMessage().contains("InvalidParameterValue")) {
|
||||
log.error("参数值错误,请检查:\n1. 分页参数 Offset 和 Limit 是否有效\n2. 搜索条件是否合法\n3. 排序参数是否正确");
|
||||
} else if (e.getMessage().contains("UnauthorizedOperation")) {
|
||||
log.error("未授权操作,请检查:\n1. 密钥是否有权限\n2. 应用 ID 是否正确\n3. 是否开通了点播服务");
|
||||
}
|
||||
throw new RuntimeException("搜索媒体文件失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证搜索请求参数
|
||||
*/
|
||||
private void validateSearchRequest(SearchMediaRequest req) {
|
||||
// 验证分页参数
|
||||
if (req.getOffset() < 0) {
|
||||
throw new IllegalArgumentException("Offset 不能小于 0");
|
||||
}
|
||||
if (req.getLimit() < 1 || req.getLimit() > 50) {
|
||||
throw new IllegalArgumentException("Limit 必须在 1-50 之间");
|
||||
}
|
||||
if (req.getOffset() + req.getLimit() > 5000) {
|
||||
throw new IllegalArgumentException("Offset + Limit 不能超过 5000");
|
||||
}
|
||||
|
||||
// 验证搜索条件
|
||||
if (req.getFileIds() != null && req.getFileIds().length > 10) {
|
||||
throw new IllegalArgumentException("FileIds 数组长度不能超过 10");
|
||||
}
|
||||
if (req.getNames() != null && req.getNames().length > 10) {
|
||||
throw new IllegalArgumentException("Names 数组长度不能超过 10");
|
||||
}
|
||||
if (req.getNamePrefixes() != null && req.getNamePrefixes().length > 10) {
|
||||
throw new IllegalArgumentException("NamePrefixes 数组长度不能超过 10");
|
||||
}
|
||||
if (req.getDescriptions() != null && req.getDescriptions().length > 10) {
|
||||
throw new IllegalArgumentException("Descriptions 数组长度不能超过 10");
|
||||
}
|
||||
if (req.getClassIds() != null && req.getClassIds().length > 10) {
|
||||
throw new IllegalArgumentException("ClassIds 数组长度不能超过 10");
|
||||
}
|
||||
if (req.getTags() != null && req.getTags().length > 16) {
|
||||
throw new IllegalArgumentException("Tags 数组长度不能超过 16");
|
||||
}
|
||||
if (req.getSourceTypes() != null && req.getSourceTypes().length > 10) {
|
||||
throw new IllegalArgumentException("SourceTypes 数组长度不能超过 10");
|
||||
}
|
||||
if (req.getStreamIds() != null && req.getStreamIds().length > 10) {
|
||||
throw new IllegalArgumentException("StreamIds 数组长度不能超过 10");
|
||||
}
|
||||
if (req.getStorageRegions() != null && req.getStorageRegions().length > 20) {
|
||||
throw new IllegalArgumentException("StorageRegions 数组长度不能超过 20");
|
||||
}
|
||||
// if (req.getMediaTypes() != null && req.getMediaTypes().length > 10) {
|
||||
// throw new IllegalArgumentException("MediaTypes 数组长度不能超过 10");
|
||||
// }
|
||||
// if (req.getStatus() != null && req.getStatus().length > 10) {
|
||||
// throw new IllegalArgumentException("Status 数组长度不能超过 10");
|
||||
// }
|
||||
// if (req.getReviewResults() != null && req.getReviewResults().length > 10) {
|
||||
// throw new IllegalArgumentException("ReviewResults 数组长度不能超过 10");
|
||||
// }
|
||||
// if (req.getTrtcSdkAppIds() != null && req.getTrtcSdkAppIds().length > 10) {
|
||||
// throw new IllegalArgumentException("TrtcSdkAppIds 数组长度不能超过 10");
|
||||
// }
|
||||
// if (req.getTrtcRoomIds() != null && req.getTrtcRoomIds().length > 10) {
|
||||
// throw new IllegalArgumentException("TrtcRoomIds 数组长度不能超过 10");
|
||||
// }
|
||||
}
|
||||
|
||||
// 视频审核
|
||||
@Override
|
||||
public void auditVlog(String vlogId, Integer status, String reason) {
|
||||
// 这里假设 status=1为通过,status=2为不通过
|
||||
// 可根据实际业务调整
|
||||
// 直接更新数据库状态
|
||||
// 你可以用 VlogMapper 或 VlogService
|
||||
// 这里只做伪代码示例
|
||||
// vlogMapper.updateStatus(vlogId, status, reason);
|
||||
log.info("审核视频 vlogId={}, status={}, reason={}", vlogId, status, reason);
|
||||
}
|
||||
|
||||
// 视频删除
|
||||
@Override
|
||||
public void deleteVlog(String vlogId) {
|
||||
// 逻辑删除或物理删除
|
||||
// vlogMapper.deleteById(vlogId);
|
||||
log.info("删除视频 vlogId={}", vlogId);
|
||||
}
|
||||
|
||||
// 视频详情
|
||||
@Override
|
||||
public Object getVlogDetail(String vlogId) {
|
||||
try {
|
||||
// 1. 优先从 MySQL 获取视频基础信息
|
||||
Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("vlogId", vlogId);
|
||||
List<com.wzj.soopin.content.domain.vo.IndexVlogVO> vlogList = vlogMapperCustom.getVlogDetailById(paramMap);
|
||||
com.wzj.soopin.content.domain.vo.IndexVlogVO vlog = vlogList != null && !vlogList.isEmpty() ? vlogList.get(0) : null;
|
||||
|
||||
com.tencentcloudapi.vod.v20180717.models.MediaInfo mediaInfo = null;
|
||||
if (vlog == null) {
|
||||
// 若本地无,尝试从云点播获取
|
||||
com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosRequest req = new com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosRequest();
|
||||
req.setFileIds(new String[]{vlogId});
|
||||
VodClient client = tencentCloudUtil.getVodClient();
|
||||
com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosResponse resp = client.DescribeMediaInfos(req);
|
||||
if (resp.getMediaInfoSet() != null && resp.getMediaInfoSet().length > 0) {
|
||||
mediaInfo = resp.getMediaInfoSet()[0];
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 点赞数量:优先 Redis,无则 MySQL
|
||||
String likeCountsStr = redis.get(com.wzj.soopin.content.domain.base.BaseInfoProperties.REDIS_VLOG_BE_LIKED_COUNTS + ":" + vlogId);
|
||||
int likeCounts;
|
||||
if (likeCountsStr != null) {
|
||||
likeCounts = Integer.parseInt(likeCountsStr);
|
||||
} else if (vlog != null && vlog.getLikeCounts() != null) {
|
||||
likeCounts = vlog.getLikeCounts();
|
||||
} else {
|
||||
likeCounts = 0;
|
||||
}
|
||||
|
||||
// 3. 评论数量:优先 Redis,无则 MySQL
|
||||
String commentCountsStr = redis.get(com.wzj.soopin.content.domain.base.BaseInfoProperties.REDIS_VLOG_COMMENT_COUNTS + ":" + vlogId);
|
||||
int commentCounts;
|
||||
if (commentCountsStr != null) {
|
||||
commentCounts = Integer.parseInt(commentCountsStr);
|
||||
} else if (vlog != null && vlog.getCommentsCounts() != null) {
|
||||
commentCounts = vlog.getCommentsCounts();
|
||||
} else {
|
||||
commentCounts = 0;
|
||||
}
|
||||
|
||||
// 4. 评论内容:只查 MySQL
|
||||
List<com.wzj.soopin.content.domain.vo.CommentVO> commentList = new ArrayList<>();
|
||||
try {
|
||||
com.wzj.soopin.content.utils.PagedGridResult pagedGridResult = commentService.queryVlogComments(vlogId, null, 1, 10);
|
||||
if (pagedGridResult != null && pagedGridResult.getRows() != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<com.wzj.soopin.content.domain.vo.CommentVO> tempList = (List<com.wzj.soopin.content.domain.vo.CommentVO>) pagedGridResult.getRows();
|
||||
if (tempList != null) {
|
||||
commentList = tempList;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("获取评论列表失败: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 5. 统一返回
|
||||
java.util.Map<String, Object> detail = new java.util.HashMap<>();
|
||||
detail.put("videoInfo", vlog != null ? vlog : mediaInfo);
|
||||
detail.put("likeCounts", likeCounts);
|
||||
detail.put("commentCounts", commentCounts);
|
||||
detail.put("commentList", commentList);
|
||||
return detail;
|
||||
} catch (Exception e) {
|
||||
log.error("获取视频详情失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ package com.wzj.soopin.content.utils;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@ -13,9 +12,34 @@ import org.springframework.stereotype.Component;
|
||||
*/
|
||||
@Component
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "tencent.cloud")
|
||||
public class TencentCloudProperties {
|
||||
|
||||
/**
|
||||
* 密钥ID
|
||||
*/
|
||||
private String secretId;
|
||||
|
||||
/**
|
||||
* 密钥Key
|
||||
*/
|
||||
private String secretKey;
|
||||
|
||||
/**
|
||||
* 区域
|
||||
*/
|
||||
private String region;
|
||||
|
||||
/**
|
||||
* 点播配置
|
||||
*/
|
||||
private Vod vod = new Vod();
|
||||
|
||||
@Data
|
||||
public static class Vod {
|
||||
/**
|
||||
* 应用ID
|
||||
*/
|
||||
private String appId;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,176 @@
|
||||
package com.wzj.soopin.content.utils;
|
||||
|
||||
import com.tencentcloudapi.common.Credential;
|
||||
import com.tencentcloudapi.common.profile.ClientProfile;
|
||||
import com.tencentcloudapi.common.profile.HttpProfile;
|
||||
import com.tencentcloudapi.vod.v20180717.VodClient;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* 腾讯云工具类
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class TencentCloudUtil {
|
||||
|
||||
@Autowired
|
||||
private TencentCloudProperties properties;
|
||||
/**
|
||||
* 获取VOD客户端实例
|
||||
*
|
||||
* @return VodClient实例
|
||||
*/
|
||||
public VodClient getVodClient() {
|
||||
// 从配置中获取值
|
||||
String secretId = properties.getSecretId();
|
||||
String secretKey = properties.getSecretKey();
|
||||
String region = properties.getRegion();
|
||||
String appId = properties.getVod().getAppId();
|
||||
|
||||
// 详细的配置检查日志
|
||||
log.info("开始初始化腾讯云 VOD 客户端");
|
||||
log.info("配置检查 - SecretId长度: {}, SecretKey长度: {}, Region: {}, AppId: {}",
|
||||
secretId != null ? secretId.length() : 0,
|
||||
secretKey != null ? secretKey.length() : 0,
|
||||
region,
|
||||
appId);
|
||||
|
||||
// 检查密钥格式
|
||||
if (secretId == null || secretId.isEmpty()) {
|
||||
throw new IllegalArgumentException("SecretId 不能为空");
|
||||
}
|
||||
if (secretKey == null || secretKey.isEmpty()) {
|
||||
throw new IllegalArgumentException("SecretKey 不能为空");
|
||||
}
|
||||
if (region == null || region.isEmpty()) {
|
||||
throw new IllegalArgumentException("Region 不能为空");
|
||||
}
|
||||
|
||||
// 检查密钥格式
|
||||
if (secretId.contains(" ")) {
|
||||
log.warn("SecretId 包含空格,这可能导致签名验证失败");
|
||||
secretId = secretId.trim();
|
||||
}
|
||||
if (secretKey.contains(" ")) {
|
||||
log.warn("SecretKey 包含空格,这可能导致签名验证失败");
|
||||
secretKey = secretKey.trim();
|
||||
}
|
||||
|
||||
// 输出服务器时间和时区信息
|
||||
LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
|
||||
LocalDateTime utcNow = LocalDateTime.now(ZoneId.of("UTC"));
|
||||
log.info("服务器时间 - 本地: {}, UTC: {}, 时区: {}",
|
||||
now.format(DateTimeFormatter.ISO_DATE_TIME),
|
||||
utcNow.format(DateTimeFormatter.ISO_DATE_TIME),
|
||||
ZoneId.systemDefault().getId());
|
||||
|
||||
// 检查密钥编码
|
||||
try {
|
||||
byte[] secretIdBytes = secretId.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] secretKeyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
// 检查密钥格式
|
||||
if (secretIdBytes.length != 36) {
|
||||
log.warn("SecretId 长度异常: {}, 预期长度: 36", secretIdBytes.length);
|
||||
}
|
||||
if (secretKeyBytes.length != 64) {
|
||||
log.warn("SecretKey 长度异常: {}, 预期长度: 64", secretKeyBytes.length);
|
||||
}
|
||||
|
||||
// 检查密钥字符
|
||||
if (!secretId.matches("^[A-Za-z0-9]+$")) {
|
||||
log.warn("SecretId 包含非字母数字字符");
|
||||
}
|
||||
if (!secretKey.matches("^[A-Za-z0-9]+$")) {
|
||||
log.warn("SecretKey 包含非字母数字字符");
|
||||
}
|
||||
|
||||
log.info("密钥编码检查 - SecretId UTF-8长度: {}, Base64: {}",
|
||||
secretIdBytes.length,
|
||||
Base64.getEncoder().encodeToString(secretIdBytes));
|
||||
log.info("密钥编码检查 - SecretKey UTF-8长度: {}, Base64: {}",
|
||||
secretKeyBytes.length,
|
||||
Base64.getEncoder().encodeToString(secretKeyBytes));
|
||||
} catch (Exception e) {
|
||||
log.error("密钥编码检查失败", e);
|
||||
throw new IllegalArgumentException("密钥编码检查失败: " + e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
// **添加日志,确认Credential和VodClient实例化前使用的实际密钥和AppId**
|
||||
log.info("实例化 Credential 和 VodClient - SecretId: {}, SecretKey长度: {}, Region: {}, AppId: {}",
|
||||
secretId != null ? secretId.substring(0, 4) + "****" : "null", // 隐藏部分密钥
|
||||
secretKey != null ? secretKey.length() : 0,
|
||||
region,
|
||||
appId);
|
||||
|
||||
// 实例化一个认证对象
|
||||
Credential cred = new Credential(secretId, secretKey);
|
||||
|
||||
// 实例化要请求产品的client对象
|
||||
VodClient client = new VodClient(cred, region);
|
||||
log.info("腾讯云 VOD 客户端初始化成功 (地域参数: {})", region);
|
||||
return client;
|
||||
} catch (Exception e) {
|
||||
log.error("初始化腾讯云 VOD 客户端失败", e);
|
||||
throw new RuntimeException("初始化腾讯云 VOD 客户端失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取密钥ID
|
||||
*
|
||||
* @return 密钥ID
|
||||
*/
|
||||
public String getSecretId() {
|
||||
return properties.getSecretId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取密钥Key
|
||||
*
|
||||
* @return 密钥Key
|
||||
*/
|
||||
public String getSecretKey() {
|
||||
return properties.getSecretKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用ID
|
||||
*
|
||||
* @return 应用ID
|
||||
*/
|
||||
public String getAppId() {
|
||||
return properties.getVod().getAppId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取视频播放地址
|
||||
*
|
||||
* @param fileId 视频文件ID
|
||||
* @return 播放地址
|
||||
*/
|
||||
public String getVideoPlayUrl(String fileId) {
|
||||
// TODO: 实现获取视频播放地址的逻辑
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取视频封面地址
|
||||
*
|
||||
* @param fileId 视频文件ID
|
||||
* @return 封面地址
|
||||
*/
|
||||
public String getVideoCoverUrl(String fileId) {
|
||||
// TODO: 实现获取视频封面地址的逻辑
|
||||
return null;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user