YouTube-Transkript in Ruby: Net::HTTP und Null Gems

Der Ruby-Reflex ist bundle add something bevor du eine Codezeile schreibst. Widerstehe dem fünf Minuten: Ein YouTube-Transkript in Ruby abzurufen braucht nichts außerhalb der Standard Library, weil die API ein HTTPS-GET ist, das JSON zurückgibt, und net/http plus json sitzen seit immer in jedem Ruby-Install. Am Ende dieses Beitrags hast du ein Skript, das jede YouTube-URL nimmt und den Video-Titel und das Transkript druckt, mit einer case-Anweisung, die jeden Fehler abdeckt, den die API zurückgibt — und ein leeres Gemfile.
Ja, Net::HTTP-Interface ist so unbeholfen, wie sein Ruf. Es ist immer noch nur zwanzig Zeilen.
Das Skript
require "net/http"
require "json"
require "uri"
uri = URI("https://youtube2text.org/api/transcribe")
uri.query = URI.encode_www_form(
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
)
req = Net::HTTP::Get.new(uri)
req["x-api-key"] = ENV.fetch("YT2TEXT_KEY")
res = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: true, read_timeout: 60) do |http|
http.request(req)
end
data = JSON.parse(res.body)
if res.is_a?(Net::HTTPSuccess)
transcript = data["result"]
puts transcript["title"]
puts "#{transcript['contentSize']} chars, truncated: #{transcript['truncated']}"
puts transcript["content"][0, 400]
else
err = data["error"]
case err["code"]
when "RATE_LIMIT_EXCEEDED"
puts "Rate limited. Retry in #{err['retryAfterSeconds']}s."
when "TRANSCRIPT_UNAVAILABLE"
puts "No captions on this video. Skip it."
when "VIDEO_NOT_FOUND", "INVALID_URL"
puts "Bad video reference: #{err['message']}"
else
abort "#{err['code']}: #{err['message']}"
end
end
Der url-Parameter ist nachgiebig — vollständige Watch-URLs, youtu.be Kurzlinks, Shorts oder eine nackte 11-stellige Video-ID funktioniert alle. Füge maxChars: 20000 zu encode_www_form hinzu, wenn das Transkript in einen LLM-Prompt geht und du lieber nicht für einen drei-Stunden-Podcast Token zahlst; 150000 ist die Standard und das Maximum.
Wenn dein Codebase bereits Faraday oder httparty hat, gut, nutze sie — die Anfrage ist die gleichen drei Zutaten: der Endpunkt, eine Query-String und eine Kopfzeile. Sprechend davon, req["Authorization"] = "Bearer #{key}" funktioniert identisch zu x-api-key, wenn Bearer-Token besser zu deinem Setup passen.
Ein Schlüssel in einem Befehl
curl https://youtube2text.org/api/demo-key
Das gibt {"success":true,"apiKey":"yt_..."} ohne Konto, ohne E-Mail, nichts zurück. Der Haken: Es ist ein gemeinsamer Schlüssel für alle anonymen Benutzer, begrenzt auf 5 Videos pro Monat pro IP. Großartig zum Verifizieren, das Skript funktioniert, falsch für alles, das du bereitstellen würdest.
Was das Transkript eigentlich ist
Es lohnt sich hier klar zu sehen: Der Text stammt von YouTubes Untertitelspuren. Manuell hochgeladene Untertitel lesen wunderschön; automatisch generierte Mangelarten gelegentlich Jargon und Produktnamen, und es gibt nichts, was API darüber kan upstream. Englische Spuren sind bevorzugt, mit Fallback zur ersten verfügbaren Sprache. Und ein Video mit deaktivierten Untertiteln gibt TRANSCRIPT_UNAVAILABLE zurück — der case-Branch oben behandelt es als Überspringen, nicht Retry, weil ein Video wieder zu versuchen, das keine Untertitel hat, ist ein sehr geduldiger Weg, um nichts zu erreichen.
Wohin Rubyists das nehmen
Das Muster, das ich am meisten sehe, ist Batch-Verarbeitung: über Video-IDs eines Kanals loopen, jeden Transkript abrufen, ihn zu etwas Downstream füttern. Studieren drehen Vorträge Videos in Study Notes; wenn der Downstream Claude ist, verbindet die freie Transkripte in Claude Durchgang die zwei ohne benutzerdefinierte Klebstoff. Der gleiche Endpunkt von PHP ist fast Zeile-für-Zeile identisch — Vergleich hier, wenn dein Team beide läuft.
Wenn der gemeinsame Demo-Schlüssel austrocknet, melde dich mit Google bei youtube2text.org/app/keys an — kein Telefon, keine Karte. Du bekommst deinen eigenen kostenlosen Schlüssel bei 5 Videos pro Monat, mit bezahlten Stufen ab $5,99 für 50 bis $19,99 unbegrenzt. Das Skript ändert sich nicht; ENV["YT2TEXT_KEY"] macht es.