using System.Net.Http.Json;
using System.Text.Json.Nodes;
using Dpz.Core.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace Dpz.Core.Service.ObjectStorage.VideoHandle;

public class VideoPretreatment(
    HttpClient httpClient,
    ILogger<VideoPretreatment> logger,
    IConfiguration configuration,
    UpyunOperator upyunOperator
)
{
    public async Task SliceAsync(string source, string name)
    {
        var argument = new PretreatmentArgument
        {
            Service = upyunOperator.Bucket ?? throw new InvalidConfigurationException(),
            NotifyUrl = configuration["NotifyUrl"] ?? throw new InvalidConfigurationException(),
            Source = source,
            Tasks =
            [
                new PretreatmentTask
                {
                    Type = "video",
                    AvOpts = [new 切片(5), new 视频分辨率()],
                    SaveAs = $"/Video/{name}/1080p.m3u8",
                },
            ],
        };

        var request = new HttpRequestMessage(HttpMethod.Post, "pretreatment");
        request.Content = new FormUrlEncodedContent([
            new KeyValuePair<string, string>("service", argument.Service),
            new KeyValuePair<string, string>("notify_url", argument.NotifyUrl),
            new KeyValuePair<string, string>("source", argument.Source),
            new KeyValuePair<string, string>("tasks", argument.TasksBase64String()),
            new KeyValuePair<string, string>("Accept", argument.Accept),
        ]);

        await request.SignatureAsync(upyunOperator);
        var response = await httpClient.SendAsync(request);

        if (!response.IsSuccessStatusCode)
        {
            logger.LogError("pretreatment fail,status code:{StatusCode}", response.StatusCode);
            throw new BusinessException(
                $"pretreatment fail,response status code:{response.StatusCode}"
            );
        }

        var taskIds = await response.Content.ReadFromJsonAsync<List<string>>();
        if (taskIds == null || taskIds.Count == 0)
        {
            logger.LogWarning("pretreatment fail,task ids is empty");
            return;
        }

        await QueryTaskResultAsync(taskIds[0]);
    }

    public async Task QueryTaskResultAsync(string taskId)
    {
        var request = new HttpRequestMessage(
            HttpMethod.Get,
            $"status?service={upyunOperator.Bucket}&task_ids={taskId}"
        );
        await request.SignatureAsync(upyunOperator);
        var response = await httpClient.SendAsync(request);
        if (!response.IsSuccessStatusCode)
        {
            logger.LogError("query task result fail,status code:{StatusCode}", response.StatusCode);
            throw new BusinessException(
                $"query task result fail,response status code:{response.StatusCode}"
            );
        }

        var json = await response.Content.ReadAsStringAsync();

        var root = JsonNode.Parse(json);
        var status = root?["tasks"]?[taskId]?.GetValue<decimal?>();

        if (status == null)
        {
            logger.LogWarning("query task result fail,task status is null,data :{Data}", json);
        }
        if (status is null or < 100)
        {
            logger.LogInformation("task is processing : {Process}%", status ?? 0);
            await Task.Delay(TimeSpan.FromSeconds(3));
            await QueryTaskResultAsync(taskId);
            return;
        }

        logger.LogInformation("task is processed");
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

这是一个用于视频预处理的服务类,主要功能是将视频文件进行切片处理并查询处理状态。让我详细解释一下各个部分:

类的整体结构

public class VideoPretreatment(
    HttpClient httpClient,
    ILogger<VideoPretreatment> logger,
    IConfiguration configuration,
    UpyunOperator upyunOperator
)

这是一个使用了 C# 12 主构造函数语法的类,通过依赖注入接收四个依赖项:

  • HttpClient:用于发送HTTP请求
  • ILogger:用于记录日志
  • IConfiguration:用于读取配置
  • UpyunOperator:又拍云操作器,用于云存储相关操作

主要方法分析

1. SliceAsync 方法

这是视频切片的主要方法:

public async Task SliceAsync(string source, string name)

功能流程:

  1. 构建请求参数:创建一个 PretreatmentArgument 对象,包含:

    • 服务名称(从upyunOperator获取)
    • 回调通知URL
    • 源文件路径
    • 处理任务配置(视频切片,5秒一片,保存为1080p.m3u8格式)
  2. 发送HTTP请求

    • 使用POST方法调用"pretreatment"接口
    • 将参数以表单形式提交
    • 对请求进行签名(通过SignatureAsync扩展方法)
  3. 处理响应

    • 检查响应状态码
    • 解析返回的任务ID列表
    • 调用查询方法监控任务状态

2. QueryTaskResultAsync 方法

这是查询任务处理状态的递归方法:

public async Task QueryTaskResultAsync(string taskId)

功能流程:

  1. 发送查询请求:使用GET方法查询指定任务的状态
  2. 解析响应:从JSON响应中提取任务状态进度
  3. 状态判断
    • 如果状态为null:记录警告日志
    • 如果进度小于100%:等待3秒后递归调用自身继续查询
    • 如果进度达到100%:任务完成,记录信息日志

关键特性

  1. 异步处理:所有方法都是异步的,使用async/await模式
  2. 错误处理:包含完整的错误处理和日志记录
  3. 递归查询:使用递归方式轮询任务状态,直到完成
  4. 配置驱动:通过配置文件获取关键参数
  5. 签名认证:对HTTP请求进行签名,确保安全性

使用场景

这个类主要用于视频处理服务,特别是:

  • 将长视频切片成HLS格式(m3u8)
  • 转换视频分辨率
  • 异步监控视频处理进度
  • 集成又拍云存储服务

整体来说,这是一个设计良好的视频预处理服务类,具有完整的错误处理、日志记录和异步处理能力。

评论加载中...