using Dpz.Core.Public.ViewModel.Response;
using Dpz.Core.Shard.Service;
using Dpz.Core.WebApi.Models.Request;
using Color = System.Drawing.Color;
namespace Dpz.Core.WebApi.Controllers;
/// <summary>
/// 视频
/// </summary>
[ApiController, Route("api/[controller]")]
public class VideoController(
IBarrageService barrageService,
IVideoService videoService,
IFusionCache fusionCache,
IVideoShardService videoShardService,
IVideoCloudService videoCloudService
) : ControllerBase
{
/// <summary>
/// 获取视频列表
/// </summary>
/// <returns></returns>
[HttpGet]
[ProducesResponseType<List<VmVideo>>(StatusCodes.Status200OK)]
public async Task<IActionResult> GetVideos()
{
var videos = await videoShardService.GetVideosAsync();
return Ok(videos);
}
/// <summary>
/// 发送弹幕
/// </summary>
/// <param name="danmaku"></param>
/// <returns></returns>
[HttpPost("danmaku")]
[ProducesResponseType<VmBarrage>(StatusCodes.Status200OK)]
public async Task<IActionResult> Danmaku([FromBody] VideoDanmakuDto danmaku)
{
var vmBarrage = new VmBarrage
{
Color = danmaku.Color.ToString(),
Group = danmaku.Id,
Position = (int)danmaku.Type,
SendTime = DateTime.Now,
Size = 0,
Text = danmaku.Text,
Time = danmaku.Time,
};
await barrageService.AddBarrageAsync(vmBarrage);
return Ok(vmBarrage);
}
/// <summary>
/// 获取视频弹幕
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("danmaku")]
[ProducesResponseType<List<VmBarrage>>(StatusCodes.Status200OK)]
public async Task<IActionResult> Danmaku(string id)
{
var danmakuList = await barrageService.GetGroupBarragesAsync(id);
danmakuList.ForEach(x =>
{
if (int.TryParse(x.Color, out var color))
{
var colorRgb = Color.FromArgb(color);
x.Color = $"rgb({colorRgb.R},{colorRgb.G},{colorRgb.B})";
}
});
return Ok(danmakuList);
}
/// <summary>
/// 获取视频详情列表
/// </summary>
/// <returns></returns>
[HttpGet("details"), Authorize(Policy = "System")]
[ProducesResponseType<List<VmVideo>>(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> GetVideoListDetails()
{
var videos = await videoShardService.GetVideosAsync();
return Ok(videos);
}
/// <summary>
/// 保存视频信息
/// </summary>
/// <returns></returns>
[HttpPost, Authorize(Policy = "System")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> SaveInformation([FromBody] VmVideo video)
{
await videoService.SaveInformationAsync(video);
await fusionCache.RemoveByTagAsync(CacheKey.VideoListKey);
return NoContent();
}
/// <summary>
/// 添加一次播放次数
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpPatch("play/{id}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> AddPlayer(string id)
{
await videoShardService.AddPlayAsync(id);
return NoContent();
}
/// <summary>
/// 获取视频元数据
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("meta/{id}"), Authorize(Policy = "System")]
[ProducesResponseType<VideoMetaDataResponse>(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetVideoMetaData(string id)
{
var videMetaKey = $"Video-Meta:{id}";
var cacheValue = await fusionCache.TryGetAsync<VideoMetaDataResponse>(videMetaKey);
if (cacheValue is { HasValue: true, Value: not null })
{
return Ok(cacheValue.Value);
}
var video = await videoShardService.GetVideoAsync(id);
if (video == null)
{
return NotFound();
}
var meta = await videoCloudService.GetVideoMetaAsync(
$"/Video/{video.Title}/1080p.m3u8",
HttpContext.RequestAborted
);
if (meta.Success)
{
await fusionCache.SetAsync(videMetaKey, meta.Data, TimeSpan.FromDays(90));
return Ok(meta.Data);
}
return BadRequest(meta.Message);
}
/// <summary>
/// 设置视频缩略图
/// </summary>
/// <param name="id"></param>
/// <param name="request"></param>
/// <returns></returns>
[HttpPatch("screenshot/{id}"), Authorize(Policy = "System")]
[ProducesResponseType<string>(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> SetVideoScreenshot(
string id,
[FromBody] ScreenshotRequest request
)
{
var video = await videoShardService.GetVideoAsync(id);
if (video == null)
{
return NotFound();
}
var meta = await videoCloudService.GetVideoMetaAsync(
$"/Video/{video.Title}/1080p.m3u8",
HttpContext.RequestAborted
);
if (!meta.Success)
{
return BadRequest(meta.Message);
}
if (request.Seconds > meta.Data?.Duration || request.Seconds < 0)
{
return BadRequest("时间超出范围");
}
var screenshot = await videoCloudService.VideoScreenshotAsync(
$"/Video/{video.Title}/1080p.m3u8",
TimeSpan.FromSeconds(request.Seconds),
HttpContext.RequestAborted
);
if (!screenshot.Success)
{
return BadRequest(screenshot.Message);
}
return Ok(screenshot.Data);
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
代码解释
这是一个基于 ASP.NET Core 的视频管理 WebAPI 控制器,提供了视频和弹幕相关的功能接口。
整体架构
控制器定义:
- 使用主构造函数(Primary Constructor)注入5个服务依赖
- 路由前缀:
/api/video - 包含视频管理、弹幕管理、播放统计等核心功能
主要功能接口
1. GetVideos - 获取视频列表
[HttpGet]
- 公开接口,无需授权
- 通过
videoShardService获取视频列表 - 返回
List<VmVideo>
2. Danmaku (POST) - 发送弹幕
[HttpPost("danmaku")]
- 接收弹幕数据并转换为
VmBarrage对象 - 关键字段映射:颜色、分组(视频ID)、位置、时间等
- 保存到数据库并返回弹幕对象
3. Danmaku (GET) - 获取视频弹幕
[HttpGet("danmaku")]
- 根据视频ID获取弹幕列表
- 颜色转换:将整数颜色值转为 RGB 格式字符串(如
rgb(255,0,0))
4. GetVideoListDetails - 获取视频详情列表
[HttpGet("details"), Authorize(Policy = "System")]
- 需要系统权限
- 返回完整视频详情列表
5. SaveInformation - 保存视频信息
[HttpPost, Authorize(Policy = "System")]
- 需要系统权限
- 保存视频信息后清除缓存(通过 Tag 方式)
- 返回 204 NoContent
6. AddPlayer - 增加播放次数
[HttpPatch("play/{id}")]
- 公开接口
- 统计视频播放量
7. GetVideoMetaData - 获取视频元数据
[HttpGet("meta/{id}"), Authorize(Policy = "System")]
- 需要系统权限
- 实现缓存策略:90天缓存周期
- 从云服务获取 m3u8 视频元数据(分辨率、时长等)
- 缓存 Key 格式:
Video-Meta:{id}
8. SetVideoScreenshot - 设置视频缩略图
[HttpPatch("screenshot/{id}"), Authorize(Policy = "System")]
- 需要系统权限
- 验证时间参数是否在视频时长范围内
- 调用云服务在指定时间点截图
- 返回截图数据
技术特点
- 依赖注入:使用 C# 12 主构造函数语法简化依赖注入
- 缓存策略:使用 FusionCache 实现分布式缓存
- 授权控制:部分接口需要 "System" 策略授权
- 响应规范:使用
ProducesResponseType明确 API 响应类型 - 分层架构:控制器调用 Service 层处理业务逻辑
- 取消令牌:支持请求取消(
HttpContext.RequestAborted)
业务场景
适用于在线视频平台的后台管理,包括:
- 视频内容管理
- 实时弹幕系统
- 播放数据统计
- 视频云存储集成(基于 m3u8 流媒体协议)
AI 正在分析代码…
评论加载中...