You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
214 lines
7.8 KiB
214 lines
7.8 KiB
package com.campus.controller;
|
|
|
|
import com.campus.common.Result;
|
|
import com.campus.dto.response.VodUploadCredential;
|
|
import com.campus.service.VodService;
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.springframework.web.bind.annotation.*;
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
|
import java.io.IOException;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* 阿里云 VOD 视频点播接口
|
|
*
|
|
* 上传流程:
|
|
* 1. POST /api/vod/upload → 前端发送视频文件 → 后端 CreateUploadVideo + 上传到 VOD Bucket
|
|
* 2. VOD 自动转码/审核 → 回调 POST /api/oss/vod-callback → 更新数据库
|
|
*
|
|
* 播放流程:
|
|
* 3. GET /api/vod/play-auth/{videoId} → 获取 PlayAuth → 前端初始化播放器
|
|
*/
|
|
@Slf4j
|
|
@RestController
|
|
@RequestMapping("/api/vod")
|
|
@RequiredArgsConstructor
|
|
public class VodController {
|
|
|
|
private final VodService vodService;
|
|
|
|
/**
|
|
* 上传视频到 VOD(一步完成:创建凭证 + 上传到 VOD Bucket)
|
|
*
|
|
* POST /api/vod/upload
|
|
* Content-Type: multipart/form-data
|
|
* 参数: file (视频文件)
|
|
*
|
|
* @return { videoId, requestId }
|
|
*/
|
|
@PostMapping("/upload")
|
|
public Result<Map<String, Object>> uploadVideo(@RequestParam("file") MultipartFile file) {
|
|
if (file.isEmpty()) {
|
|
return Result.error(400, "文件不能为空");
|
|
}
|
|
|
|
String fileName = file.getOriginalFilename();
|
|
if (fileName == null) {
|
|
fileName = "video.mp4";
|
|
}
|
|
|
|
try {
|
|
// Step 1: 创建上传凭证(CreateUploadVideo)
|
|
log.info("开始VOD上传: fileName={}, size={}MB", fileName,
|
|
String.format("%.1f", file.getSize() / 1024.0 / 1024.0));
|
|
VodUploadCredential credential = vodService.createUploadVideo(fileName);
|
|
|
|
// Step 2: 使用临时凭证上传到 VOD Bucket
|
|
String videoId = vodService.uploadToVodBucket(
|
|
file.getInputStream(),
|
|
file.getSize(),
|
|
credential,
|
|
file.getContentType()
|
|
);
|
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
result.put("videoId", videoId);
|
|
result.put("requestId", credential.getRequestId());
|
|
|
|
log.info("VOD上传完成: videoId={}", videoId);
|
|
return Result.success(result);
|
|
|
|
} catch (IOException e) {
|
|
log.error("VOD上传失败: 文件读取错误", e);
|
|
return Result.error(500, "文件读取失败: " + e.getMessage());
|
|
} catch (Exception e) {
|
|
log.error("VOD上传失败: fileName={}", fileName, e);
|
|
return Result.error(500, "视频上传失败: " + e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 上传图片到 VOD(一步完成:创建凭证 + 上传到 VOD Bucket)
|
|
*
|
|
* POST /api/vod/upload-image
|
|
* Content-Type: multipart/form-data
|
|
* 参数: file (图片文件)
|
|
*
|
|
* @return { imageId, imageUrl, requestId }
|
|
*/
|
|
@PostMapping("/upload-image")
|
|
public Result<Map<String, Object>> uploadImage(@RequestParam("file") MultipartFile file) {
|
|
if (file.isEmpty()) {
|
|
return Result.error(400, "文件不能为空");
|
|
}
|
|
|
|
String fileName = file.getOriginalFilename();
|
|
if (fileName == null) {
|
|
fileName = "image.jpg";
|
|
}
|
|
|
|
try {
|
|
log.info("开始VOD图片上传: fileName={}, size={}KB", fileName,
|
|
String.format("%.1f", file.getSize() / 1024.0));
|
|
|
|
// Step 1: 创建上传凭证(CreateUploadImage)
|
|
VodUploadCredential credential = vodService.createUploadImage(fileName);
|
|
|
|
// Step 2: 使用临时凭证上传到 VOD Bucket
|
|
String imageId = vodService.uploadToVodBucket(
|
|
file.getInputStream(),
|
|
file.getSize(),
|
|
credential,
|
|
file.getContentType()
|
|
);
|
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
result.put("imageId", imageId);
|
|
result.put("imageUrl", credential.getImageUrl());
|
|
result.put("requestId", credential.getRequestId());
|
|
|
|
log.info("VOD图片上传完成: imageId={}, imageUrl={}", imageId, credential.getImageUrl());
|
|
return Result.success(result);
|
|
|
|
} catch (IOException e) {
|
|
log.error("VOD图片上传失败: 文件读取错误", e);
|
|
return Result.error(500, "文件读取失败: " + e.getMessage());
|
|
} catch (Exception e) {
|
|
log.error("VOD图片上传失败: fileName={}", fileName, e);
|
|
return Result.error(500, "图片上传失败: " + e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 创建上传凭证(用于前端直传场景 — 高级用法,需要前端集成 OSS SDK)
|
|
*
|
|
* POST /api/vod/create-upload
|
|
* Body: { "fileName": "video.mp4" }
|
|
*
|
|
* 注意:React Native 环境下建议使用 POST /api/vod/upload,后端代理上传更稳定
|
|
*/
|
|
@PostMapping("/create-upload")
|
|
public Result<VodUploadCredential> createUpload(@RequestBody Map<String, String> body) {
|
|
String fileName = body.getOrDefault("fileName", "video.mp4");
|
|
|
|
try {
|
|
VodUploadCredential credential = vodService.createUploadVideo(fileName);
|
|
return Result.success(credential);
|
|
} catch (Exception e) {
|
|
log.error("创建上传凭证失败: fileName={}", fileName, e);
|
|
return Result.error(500, "创建上传凭证失败: " + e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 刷新上传凭证(凭证有效期 3000 秒)
|
|
*
|
|
* POST /api/vod/refresh-upload/{videoId}
|
|
*/
|
|
@PostMapping("/refresh-upload/{videoId}")
|
|
public Result<VodUploadCredential> refreshUpload(@PathVariable String videoId) {
|
|
try {
|
|
VodUploadCredential credential = vodService.refreshUploadVideo(videoId);
|
|
return Result.success(credential);
|
|
} catch (Exception e) {
|
|
log.error("刷新上传凭证失败: videoId={}", videoId, e);
|
|
return Result.error(500, "刷新上传凭证失败: " + e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取视频播放凭证(PlayAuth — 安全播放)
|
|
*
|
|
* GET /api/vod/play-auth/{videoId}
|
|
*
|
|
* 返回 PlayAuth,前端用它初始化阿里云播放器 SDK
|
|
* 同时返回视频元信息(封面、时长等)
|
|
*/
|
|
@GetMapping("/play-auth/{videoId}")
|
|
public Result<Map<String, Object>> getPlayAuth(@PathVariable String videoId) {
|
|
try {
|
|
String playAuth = vodService.getPlayAuth(videoId);
|
|
Map<String, Object> playInfo = vodService.getPlayInfo(videoId);
|
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
result.put("videoId", videoId);
|
|
result.put("playAuth", playAuth);
|
|
result.put("coverUrl", playInfo.get("coverUrl"));
|
|
result.put("duration", playInfo.get("duration"));
|
|
|
|
return Result.success(result);
|
|
} catch (Exception e) {
|
|
log.error("获取播放凭证失败: videoId={}", videoId, e);
|
|
return Result.error(500, "获取播放凭证失败: " + e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取视频播放地址(简单场景,直接返回 m3u8 URL)
|
|
*
|
|
* GET /api/vod/play-info/{videoId}
|
|
*/
|
|
@GetMapping("/play-info/{videoId}")
|
|
public Result<Map<String, Object>> getPlayInfo(@PathVariable String videoId) {
|
|
try {
|
|
Map<String, Object> playInfo = vodService.getPlayInfo(videoId);
|
|
return Result.success(playInfo);
|
|
} catch (Exception e) {
|
|
log.error("获取播放信息失败: videoId={}", videoId, e);
|
|
return Result.error(500, "获取播放信息失败: " + e.getMessage());
|
|
}
|
|
}
|
|
}
|
|
|