| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 |
- using Application.Abstractions.Data;
- using Application.Abstractions.Hub;
- using Application.Abstractions.Messaging;
- using Application.Abstractions.YouTube;
- using Domain.Entities.Members;
- using Domain.Entities.Members.ValueObject;
- using Microsoft.EntityFrameworkCore;
- using SharedKernel.Results;
- namespace Application.Features.Admin.Channel.YouTubePubSub.ForceLive;
- internal sealed class Handler(
- IAppDbContext db,
- IYouTubeLiveStateStore liveStateStore,
- IChannelStatusBroadcaster broadcaster
- ) : ICommandHandler<Command, Result>
- {
- public async Task<Result> Handle(Command request, CancellationToken ct)
- {
- if (string.IsNullOrWhiteSpace(request.YouTubeChannelID) || string.IsNullOrWhiteSpace(request.VideoID))
- {
- return Result.Failure(Error.Problem("ForceLive.Invalid", "YouTube Channel ID 와 Video ID 가 필요합니다."));
- }
- var channel = await db.Channel.AsNoTracking()
- .FirstOrDefaultAsync(c => c.YouTubeChannelID == request.YouTubeChannelID && c.IsActive, ct);
- if (channel is null)
- {
- return Result.Failure(Error.NotFound("ForceLive.ChannelNotFound", "내부 Channel 을 찾을 수 없습니다."));
- }
- var title = string.IsNullOrWhiteSpace(request.Title) ? "(수동 등록 라이브)" : request.Title!;
- var now = DateTime.UtcNow;
- // YouTube API 호출 없이 LiveStreamInfo 수동 생성 — quota 0
- var liveInfo = new YouTubeLiveStreamInfo(
- VideoId: request.VideoID,
- Title: title,
- ChannelId: request.YouTubeChannelID,
- LiveBroadcastContent: "live",
- ActiveLiveChatId: null,
- ScheduledStartTime: null,
- ActualStartTime: now,
- ViewerCount: 0,
- ViewerCountUpdatedAt: now
- );
- // Redis 라이브 상태 저장
- await liveStateStore.SetLiveAsync(request.YouTubeChannelID, liveInfo);
- // DB BroadcastSession 생성 (없으면)
- var existing = await db.BroadcastSession
- .FirstOrDefaultAsync(b => b.Platform == BroadcastPlatform.YouTube && b.VideoID == request.VideoID, ct);
- if (existing is null)
- {
- var session = BroadcastSession.Create(channel.ID, BroadcastPlatform.YouTube, request.VideoID);
- session.UpdateStats(title, now, null, 0, 0);
- db.BroadcastSession.Add(session);
- await db.SaveChangesAsync(ct);
- }
- // SignalR 브로드캐스트 → ChannelSidebar / WatchView 실시간 반영
- await broadcaster.BroadcastAsync(channel.SID, isLive: true, viewerCount: 0, videoId: request.VideoID, ct);
- return Result.Success();
- }
- }
|