📄 src/Infrastructure/YouTube/YouTubeUploader.cs
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Google.Apis.Upload;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
using Slopper.Domain;

namespace Slopper.Infrastructure.YouTube;

internal sealed class YouTubeUploader(YouTubeService youTubeService) : IUploader
{
    public async Task<UploadResult> Upload(Clip clip, CancellationToken cancellationToken)
    {
        var video = new Video()
        {
            Snippet = new()
            {
                Title = clip.Caption,
                Tags = [.. clip.Tags.Select(t => t.Value)],
                CategoryId = "1",
            },
            Status = new() { PrivacyStatus = "public" },
        };

        string? youTubeId = null;
        using (var videoStream = File.OpenRead(clip.Path))
        {
            var request = youTubeService.Videos.Insert(video, "snippet,status", videoStream, "video/mp4");
            request.ResponseReceived += v => youTubeId = v.Id;
            var progress = await request.UploadAsync(cancellationToken);
            progress.ThrowOnFailure();
        }

        if (youTubeId is null)
        {
            throw new Exception("Received no YouTube ID from upload");
        }

        return new(new($"https://www.youtube.com/shorts/{youTubeId}"));
    }
}