using Dpz.Core.Infrastructure;
using Dpz.Core.Public.ViewModel;
using Dpz.Core.Service.ObjectStorage.Services;
using Dpz.Core.Service.RepositoryService;
using Dpz.Core.Shard.Service;
using Microsoft.Extensions.Configuration;
using ZiggyCreatures.Caching.Fusion;

namespace Dpz.Core.Shard.Implement.Service;

public class VideoShardService(
    IVideoService videoService,
    IObjectStorageOperation objectStorageService,
    IFusionCache fusionCache,
    IConfiguration configuration
) : IVideoShardService
{
    private readonly string _cdnSourceHost =
        configuration["CDNSourceHost"] ?? throw new ArgumentNullException(nameof(_cdnSourceHost));

    public async Task<List<VmVideo>> GetVideosAsync()
    {
        var cacheValue = await fusionCache.TryGetAsync<List<VmVideo>>(CacheKey.VideoListKey);
        if (cacheValue.HasValue)
        {
            return cacheValue.Value;
        }

        var list = await videoService.GetVideosAsync();
        var videoList = await objectStorageService.GetFolderListAsync("/Video");
        var videos = videoList
            .Select(x =>
            {
                var video = list.FirstOrDefault(y => y.Id == x.Name.GenerateHashMd5());
                if (video != null)
                {
                    video.Cover = $"{_cdnSourceHost}/Video/{video.Title}/video.webp";
                    video.M3u8 = $"{_cdnSourceHost}/Video/{x.Name}/1080p.m3u8";
                    return video;
                }
                return new VmVideo
                {
                    Id = x.Name.GenerateHashMd5(),
                    Title = x.Name,
                    Cover = $"{_cdnSourceHost}/Video/{x.Name}/video.webp",
                    M3u8 = $"{_cdnSourceHost}/Video/{x.Name}/1080p.m3u8",
                };
            })
            .ToList();
        await fusionCache.SetAsync(
            CacheKey.VideoListKey,
            videos,
            TimeSpan.FromDays(1),
            [CacheKey.VideoListKey]
        );

        return videos;
    }

    public async Task<VmVideo?> GetVideoAsync(string id)
    {
        var key = $"{CacheKey.VideoListKey}:{id}";
        var cacheValue = await fusionCache.TryGetAsync<VmVideo>(key);
        if (cacheValue.HasValue)
        {
            return cacheValue.Value;
        }

        var video = await videoService.GetVideoAsync(id);
        if (video == null)
        {
            var folder = (await objectStorageService.GetFolderListAsync("/Video")).FirstOrDefault(
                x => x.Name.GenerateHashMd5() == id
            );
            if (folder == null)
            {
                return null;
            }

            video = new VmVideo
            {
                Description = "",
                Id = folder.Name.GenerateHashMd5(),
                Name = "",
                SubTitle = "",
                Tags = [],
                Title = folder.Name,
                VideoTitle = "",
                Cover = $"{_cdnSourceHost}/Video/{folder.Name}/video.webp",
                M3u8 = $"{_cdnSourceHost}/Video/{folder.Name}/1080p.m3u8",
                PlayCount = 0,
                DanmakuCount = 0,
                CommentCount = 0,
            };
        }
        await fusionCache.SetAsync(key, video, TimeSpan.FromDays(1), [CacheKey.VideoListKey]);
        return video;
    }

    public async Task AddPlayAsync(string id)
    {
        await videoService.AddPlayAsync(id);
        var key = $"{CacheKey.VideoListKey}:{id}";
        var cacheValue = await fusionCache.TryGetAsync<VmVideo>(key);
        if (cacheValue.HasValue)
        {
            cacheValue.Value.PlayCount++;
            await fusionCache.SetAsync(
                key,
                cacheValue.Value,
                TimeSpan.FromDays(1),
                [CacheKey.VideoListKey]
            );
        }

        var listCache = await fusionCache.TryGetAsync<List<VmVideo>>(CacheKey.VideoListKey);
        if (listCache.HasValue)
        {
            var video = listCache.Value.FirstOrDefault(x => x.Id == id);
            if (video != null)
            {
                video.PlayCount++;
                await fusionCache.SetAsync(
                    CacheKey.VideoListKey,
                    listCache.Value,
                    TimeSpan.FromDays(1),
                    [CacheKey.VideoListKey]
                );
            }
        }
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

VideoShardService 代码解析

这个 VideoShardService 类是一个视频分片服务实现,主要功能是管理视频信息并提供缓存功能。以下是它的主要功能解析:

主要功能

  1. 获取视频列表 (GetVideosAsync)

    • 首先尝试从缓存获取视频列表
    • 如果缓存没有,则:
      • 从视频服务获取视频信息
      • 从对象存储获取视频文件夹列表
      • 合并两者信息,生成完整的视频列表
      • 设置缓存(1天有效期)并返回结果
  2. 获取单个视频 (GetVideoAsync)

    • 首先尝试从缓存获取单个视频
    • 如果缓存没有,则:
      • 从视频服务获取视频详情
      • 如果服务中没有,则从对象存储查找并创建基本视频信息
      • 设置缓存(1天有效期)并返回结果
  3. 增加播放计数 (AddPlayAsync)

    • 调用视频服务增加播放计数
    • 更新缓存中的播放计数(单个视频和视频列表)

技术特点

  1. 缓存机制

    • 使用 FusionCache 进行缓存管理
    • 缓存键使用 CacheKey.VideoListKey 及其派生键
    • 缓存有效期为1天
    • 支持批量失效(通过标签)
  2. 数据源整合

    • 结合数据库(videoService)和对象存储(objectStorageService)的数据
    • 自动生成视频封面和播放地址(使用配置的CDN地址)
  3. 自动生成信息

    • 对于对象存储中存在的但数据库中不存在的视频,自动生成基本视频信息
    • 使用文件夹名生成视频ID(MD5哈希)

依赖项

  • IVideoService: 提供视频数据访问
  • IObjectStorageOperation: 提供对象存储操作
  • IFusionCache: 提供缓存功能
  • IConfiguration: 提供配置访问(如CDN地址)

使用场景

这个服务适用于需要整合多个数据源并提供高效缓存访问的视频管理系统,特别是在视频内容可能同时存在于数据库和对象存储中的场景。

评论加载中...