Transkrypcje przez YouTube Data API: dlaczego captions.download zawodzi

Jeśli próbujesz pobierać transkrypcje przez YouTube Data API, prawdopodobnie już uderzyłeś w ścianę: captions.list radośnie zwraca identyfikatory ścieżek napisów dla dowolnego filmu, ale w momencie wywołania captions.download na którejś z nich dostajesz 403. Sprawdzasz klucz API, dodajesz scope youtube.force-ssl, próbujesz OAuth — wciąż 403. To nie jest bug ani problem z limitem. Tak to zaprojektowano, a dokumentacja chowa sedno głęboko.
Ograniczenie, precyzyjnie
captions.download wymaga tokenu OAuth z konta, które jest właścicielem filmu. Nie dowolnego uwierzytelnionego konta — właściciela kanału (albo content managera z prawami do niego). Endpointy captions istnieją po to, żeby twórcy mogli zarządzać ścieżkami napisów we własnych uploadach: wgrać .srt, poprawić literówkę, usunąć nieudane automatyczne tłumaczenie. Pobieranie napisów z dowolnych cudzych filmów nigdy nie było częścią tej umowy.
Komunikat błędu mówi to wprost, gdy przeczyta się go uważnie:
The permissions associated with the request are not sufficient
to download the caption track.
Więc zwykła ścieżka eskalacji — klucz API → OAuth jako Ty → szersze scope'y → konto serwisowe — prowadzi donikąd. Każdy szczebel oblewa ten sam test własności. Spaliłem na tym popołudnie, zanim to zaakceptowałem, a sądząc po ruchu na Stack Overflow, pół internetu też.
Do czego captions.list wciąż się nadaje
Żeby być fair wobec Data API: captions.list działa ze zwykłym kluczem API i kosztuje około 50 jednostek limitu. Mówi, jakie ścieżki istnieją, w jakich językach i czy są generowane automatycznie (trackKind: "asr"), czy wgrane przez człowieka. To naprawdę przydatne jako kontrola wstępna — jeśli film nie ma żadnych ścieżek, wiesz z góry, że będziesz potrzebować speech-to-text zamiast ekstrakcji napisów. Data API pozostaje też właściwym narzędziem do wyszukiwania, wyliczania playlist i metadanych. Po prostu nie wyda Ci tekstu transkrypcji.
Opcja 1: pobieraj napisy tak jak odtwarzacz
Odtwarzacz wideo oczywiście otrzymuje dane napisów bez tokenu OAuth właściciela, a biblioteki takie jak youtube-transcript-api (Python) pobierają je tą samą drogą. Na Twoim laptopie działa to dobrze i zajmuje trzy linijki.
Haczyk ujawnia się na produkcji: YouTube agresywnie kwestionuje żądania z zakresów IP centrów danych. Wdróż te same trzy linijki na AWS, GCP albo Heroku, a zaczniesz widzieć „Sign in to confirm you're not a bot" i błędy IpBlocked. Ten tryb awarii i obejścia opisałem osobno w dlaczego youtube-transcript-api jest blokowane w chmurze — w skrócie: da się to naprawić proxy rezydencjalnymi, ale to osobny projekt.
Opcja 2: hostowane API do transkrypcji
Jeśli chcesz po prostu wyciągnąć tekst z adresu URL, hostowany endpoint omija oba problemy — bez wymogu własności, bez niańczenia proxy. youtube2text.org obsługuje pobieranie napisów po stronie serwera za rotującymi proxy rezydencjalnymi, więc Twoje żądanie może przyjść skądkolwiek:
# grab a free demo key (shared, 5 videos/month per IP)
curl -s https://youtube2text.org/api/demo-key
# fetch a transcript
curl -s "https://youtube2text.org/api/transcribe?url=https://www.youtube.com/watch?v=VIDEO_ID" \
-H "x-api-key: yt_YOUR_KEY"
Odpowiedź to zwykły JSON:
{"result": {"videoId": "...", "title": "...", "pubDate": "...",
"content": "full transcript text ...", "contentSize": 12345, "truncated": false}}
Jeśli film po prostu nie ma napisów, dostajesz TRANSCRIPT_UNAVAILABLE z kodem 404 — tę samą sytuację, którą captions.list pokazałby jako pustą listę ścieżek, tylko wykrytą w jednym wywołaniu zamiast dwóch.
Dłuższy przewodnik z obsługą błędów znajdziesz w pobieraniu transkrypcji z YouTube przez curl, a wersję w Pythonie w przewodniku migracji z youtube-transcript-api, jeśli kod oparty na requests bardziej Ci odpowiada.
Rozsądna konfiguracja łączona
Co bym dziś faktycznie zbudował, po walce z tym z obu stron:
- Data API do odkrywania — wyszukiwanie, uploady kanałów, playlisty, daty publikacji. Jest niezawodne i hojnie limitowane dla metadanych.
- Endpoint transkrypcji (hostowany, albo własny scraping z proxy, jeśli to lubisz) do właściwego tekstu.
- Speech-to-text jako fallback tylko dla filmów całkiem bez napisów.
Zmuszanie captions.download do środkowego zadania to jedyna ścieżka, która kategorycznie nie może zadziałać dla filmów, których nie posiadasz — nie zmieni tego żaden scope, klucz ani ustawienie w konsoli.
Jeśli chcesz własny klucz zamiast współdzielonego demo, logowanie jest wyłącznie przez Google na youtube2text.org/app/keys — bez numeru telefonu, bez karty. Darmowy poziom to 5 filmów miesięcznie; płatne plany zaczynają się od 5,99 USD za 50.