| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 |
- using Application.Abstractions.Data;
- using Application.Abstractions.Messaging;
- using Application.Abstractions.YouTube;
- using Microsoft.EntityFrameworkCore;
- using SharedKernel.Results;
- namespace Application.Features.Api.Channel.List;
- public sealed class Handler(IAppDbContext db, IYouTubeLiveStateStore liveStateStore, IYouTubeChannelCache channelCache) : IQueryHandler<Query, Result<Response>>
- {
- public async Task<Result<Response>> Handle(Query request, CancellationToken ct)
- {
- // 1. 활성 채널 목록 조회
- var channels = await db.Channel.AsNoTracking().Where(c => c.IsActive).Select(c => new { c.SID, c.Name, c.Handle }).ToListAsync(ct);
- if (channels.Count == 0)
- {
- return new Response([]);
- }
- // 2. YouTube 채널 정보 캐시 일괄 조회 (Redis — API 호출 0)
- var channelIds = channels.Select(c => c.SID).ToList();
- var ytCache = await channelCache.GetManyAsync(channelIds);
- // 3. 현재 라이브 중인 채널 상태 조회 (Redis — 0 unit)
- var allLive = await liveStateStore.GetAllLiveAsync();
- var liveMap = allLive.ToDictionary(l => l.ChannelId);
- // 4. 채널별 정보 조합
- var items = new List<ChannelItem>();
- foreach (var ch in channels)
- {
- var isLive = liveMap.TryGetValue(ch.SID, out var liveInfo);
- var hasYtInfo = ytCache.TryGetValue(ch.SID, out var ytInfo);
- items.Add(new ChannelItem(
- ch.SID,
- ch.Name,
- ch.Handle,
- hasYtInfo ? ytInfo!.ThumbnailUrl : null,
- hasYtInfo ? ytInfo!.SubscriberCount : 0,
- isLive,
- 0, // viewerCount — 추후 사이트 자체 접속자 수로 대체
- isLive ? liveInfo!.VideoId : null
- ));
- }
- // 5. 정렬: 온라인(시청자 많은 순) → 오프라인(이름순)
- items.Sort((a, b) => {
- if (a.IsLive && !b.IsLive) return -1;
- if (!a.IsLive && b.IsLive) return 1;
- if (a.IsLive && b.IsLive) return b.ViewerCount.CompareTo(a.ViewerCount);
- return string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase);
- });
- return new Response(items);
- }
- }
|