HomeBlogTranscribePlansAPI Keys

Transkrypcja YouTube w C# z HttpClient i Records

Aplikacja konsoli C# deserializująca odpowiedź transkrypcji YouTube za pomocą System.Text.Json

Od dotnet run do wydrukowanej transkrypcji zajęło mi około dwóch sekund na mojej maszynie, a większość z tego to podróż sieciowa. Żadne pakiety NuGet nie pojawiają się gdziekolwiek w tym poście — uzyskanie transkrypcji YouTube w C# to jedno żądanie GET, a HttpClient plus System.Text.Json były wysyłane w pudełku przez lata. Na koniec będziesz mieć kompletną aplikację konsolową z typami rekordów dla odpowiedzi, asynchroniczny Main i obsługę błędów czytającą ustrukturyzowany obiekt błędu API zamiast zgadywania na podstawie kodów stanu.

Trzy rekordy

API zwraca {"result": {...}} na sukces i {"error": {...}} na niepowodzenie, więc modeluj kopertę bezpośrednio:

public record Transcript(
    string VideoId,
    string Title,
    string PubDate,
    string Content,
    int ContentSize,
    bool Truncated);

public record ApiError(
    string Code,
    string Message,
    int Status,
    int? RetryAfterSeconds);

public record Envelope(Transcript? Result, ApiError? Error);

Jedno wywołanie Deserialize<Envelope> obsługuje każdą odpowiedź. Która właściwość jest nie-null jest Twoją odpowiedzią. RetryAfterSeconds jest nullable, ponieważ tylko błędy limitów szybkości go niosą.

Program

Celuje na .NET 8, działa tak jak jest na 6 i 7:

using System;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;

public static class Program
{
    private static readonly HttpClient Http = new();
    private static readonly JsonSerializerOptions Json =
        new(JsonSerializerDefaults.Web);

    public static async Task Main(string[] args)
    {
        var videoUrl = args.Length > 0
            ? args[0]
            : "https://www.youtube.com/watch?v=dQw4w9WgXcQ";

        var request = new HttpRequestMessage(HttpMethod.Get,
            "https://youtube2text.org/api/transcribe" +
            $"?url={Uri.EscapeDataString(videoUrl)}&maxChars=40000");
        request.Headers.Add("x-api-key",
            Environment.GetEnvironmentVariable("YT2TEXT_KEY"));

        var response = await Http.SendAsync(request);
        var envelope = JsonSerializer.Deserialize<Envelope>(
            await response.Content.ReadAsStringAsync(), Json);

        if (envelope?.Error is { } err)
        {
            Console.Error.WriteLine($"{err.Code}: {err.Message}");
            if (err.RetryAfterSeconds is int wait)
                Console.Error.WriteLine($"Retry after {wait}s");
            Environment.Exit(1);
        }

        var t = envelope!.Result!;
        Console.WriteLine($"{t.Title} ({t.ContentSize} chars, truncated: {t.Truncated})");
        Console.WriteLine(t.Content[..Math.Min(t.Content.Length, 400)]);
    }
}

JsonSerializerDefaults.Web mapuje pola API w camelCase na właściwości rekordu PascalCase, więc nie ma nawet pojedynczego atrybutu [JsonPropertyName] w zasięgu. Parametr url akceptuje każdą odmianę URL YouTube plus gołe 11-znakowe id, a nagłówek może być Authorization: Bearer yt_... zamiast x-api-key, jeśli to lepiej pasuje do Twojego middleware.

O tym maxChars=40000

maxChars ogranicza długość transkrypcji; 150000 to zarówno domyślna, jak i twarda górna granica. Jeśli napisy wideo przebiegają Twoją granicę, Truncated wraca true i otrzymujesz pierwsze N znaków — sprawdź flagę przed założeniem, że masz pełny tekst. Ustawiłem 40000 w przykładzie, ponieważ te transkrypcje zwykle kończą się w promptu LLM, a przy około czterech znakach na token to budżet 10k-tokenów. Jeśli Twoje wywołania modelu przechodzą przez API OpenAI Responses, istnieje sposób, aby pominąć całą głębiowanie HTTP całkowicie poprzez serwer MCP z OpenAI; odpowiednik Anthropic jest w używaniu transkrypcji z Claude API.

Kody błędów do rozgałęzienia

ApiError.Code to stabilny ciąg: UNAUTHORIZED (401), VALIDATION_ERROR i INVALID_URL (400), VIDEO_NOT_FOUND i TRANSCRIPT_UNAVAILABLE (404), RATE_LIMIT_EXCEEDED (429), YOUTUBE_ERROR (500). Ten, który zaskakuje ludzi, to TRANSCRIPT_UNAVAILABLE: transkrypcje pochodzą z pasów napisów YouTube, a film, którego właściciel wyłączył napisy, ma nic do zwrócenia — brak polityki ponownych prób tego naprawia. Dopasuj wzorzec do kodu, traktuj to jako permanentne pominięcie.

Aby uzyskać klucz testowy bez rejestracji, POBIERZ https://youtube2text.org/api/demo-key — jest wspólny i ograniczony do 5 filmów na miesiąc na IP, więc dotyczy eksperymentów tylko. Jeśli Go jest również w Twoim stosie, to samo wywołanie w Golang używa sztuczki koperty identycznej.

Kompletne odniesienie czytelne dla maszyn — każdy parametr, każdy błąd, gotowy do wklejenia do promptu systemu — znajduje się na youtube2text.org/api.md.