Youtube-Transscript ohne API-Key

YouTube-Transkripte ohne API: Ein kleines Skript extrahiert automatisch Untertitel.

Youtube-Transscript ohne API-Key
Photo by Mohammad Rahmani / Unsplash

Ich verfolge viele Kanäle von Security-Researchern, die die Rolle von KI in der Netzwerksicherheit diskutieren. Während es kommerzielle Produkte zur Erkennung von Angriffen gibt, bin ich skeptisch, blind auf Lösungen zu vertrauen, deren Trainingsdaten unbekannt sind. Zudem sind diese Produkte oft so teuer, sodass sie sicherlich nicht bei mir privat zum Einsatz kämen.

Das Problem

Ich verbringe oft Stunden damit, Videos zu schauen, nur um dann festzustellen, dass die relevanten Informationen für meine Projekte eher spärlich sind. Diese Zeitverschwendung ist frustrierend. Daher brauche ich im ersten Schritt eine Mitschrift des Dialogs, um daraus per KI meine Fragen effizienter beantworten zu können.

Ein Lösungsansatz

Eine Lösung für die Transkription und Analyse von YouTube-Videos habe ich bereits in meinem Beitrag über Fabric vorgestellt. Dort ist das yt Modul sehr praktisch. Doch Fabric möchte ich nicht auf jedem Rechner installieren und einen Google API-Schlüssel will ich ebenfalls nicht überall hinterlegen. Was also tun?

Die Lösung für mich ist ein kleines Skript, das auf den automatischen Untertiteln von YouTube aufbaut. Diese können mit yt-dlp heruntergeladen werden. Das Ergebnis sieht zwar zunächst unbrauchbar aus:

1
00:00:00,040 --> 00:00:03,800
<font color="white" size=".72c">lesson AI for Network traffic analysis</font>

2
00:00:02,480 --> 00:00:05,520
<font color="white" size=".72c">artificial intelligence has</font>
...

Aber mit einem einfachen sed-Befehl lässt sich der Text zwischen den <font>-Tags extrahieren:

sed -n 's/<font[^>]*>\(.*\)<[/]font>/\1/p' transcript.en.srt

Das Ergebnis ist deutlich lesbarer und mit fmt -w 100 kann ich den Text neu umbrechen:

lesson AI for Network traffic analysis artificial intelligence has revolutionized many aspects
of technology and its application in network traffic analysis forms a Cornerstone of modern
cyber security strategies Network traffic analysis involves the monitoring and examination
of network data to detect anomalies threats and inefficiencies traditional methods often fall
short when dealing with large scale complex Network environments AI with its capabilities in
...

Das fertige Skript

Hier ist das vollständige Skript, das all diese Schritte zusammenfasst:

yt() {
  # --------------------------
  # YouTube Transkript-Extraktor mit Metadaten
  # Zweck: Extrahiert Untertitel, bereinigt sie und fasst Videometadaten zusammen.
  # Verwendung: yt <YouTube_URL>
  # Abhängigkeiten: yt-dlp, jq, sed, fmt
  # --------------------------

  # Funktion zur Formatierung der Dauer in HH:MM:SS
  format_duration() {
    local total_seconds=$1
    local hours=$((total_seconds / 3600))
    local minutes=$(( (total_seconds % 3600) / 60 ))
    local seconds=$((total_seconds % 60))
    printf "%02d:%02d:%02d" $hours $minutes $seconds
  }

  # Überprüfen, ob eine URL angegeben wurde
  if [ $# -eq 0 ]; then
    echo "Fehler: Keine YouTube-Video-URL angegeben."
    echo "Verwendung: yt <YouTube_URL>"
    exit 1
  fi

  # URL aus Argument übernehmen
  URL="$1"

  # --------------------------
  # Herunterladen von Untertiteln und Metadaten
  # --------------------------
  echo "Lade Untertitel und Metadaten für: $URL herunter..." >&2
  yt-dlp --skip-download \
         --write-subs --write-auto-subs \
         --sub-lang en --sub-format ttml \
         --convert-subs srt \
         --write-info-json \
         --output "transcript.%(ext)s" \
         "$URL" > /dev/null 2>&1

  # Überprüfen, ob die Untertitel-Datei existiert
  if [ ! -f "transcript.en.srt" ]; then
    echo "Fehler: Untertitel konnten nicht heruntergeladen werden. Stellen Sie sicher, dass das Video englische Untertitel hat."
    exit 1
  fi

  # --------------------------
  # Bereinigung der Untertitel-Datei
  # --------------------------
  echo "Bereinige Untertitel-Datei..." >&2

  cat transcript.en.srt | grep -Ev "^$| --> |^[0-9]*$" | sed 's/<[^>]*>//g'| fmt -w 120 > output.txt

  # Entfernen der Zwischendatei (.srt)
  rm transcript.en.srt

  # --------------------------
  # Analyse und Zusammenfassung der Daten
  # --------------------------
  # Wörter und Zeilen zählen
  WORD_COUNT=$(wc -w < output.txt)
  LINE_COUNT=$(wc -l < output.txt)

  # Metadaten extrahieren
  if [ ! -f "transcript.info.json" ]; then
    echo "Fehler: Metadaten-Datei fehlt."
    exit 1
  fi

  TITLE=$(jq -r '.title' transcript.info.json)
  DURATION=$(jq -r '.duration' transcript.info.json)
  UPLOAD_DATE=$(jq -r '.upload_date' transcript.info.json)

  # Dauer formatieren
  DURATION_FORMATTED=$(format_duration $DURATION)

  # Zusammenfassung der Metadaten erstellen
  METADATA="Videotitel: $TITLE
  Dauer: $DURATION_FORMATTED
  Hochladedatum: ${UPLOAD_DATE:0:4}-${UPLOAD_DATE:4:2}-${UPLOAD_DATE:6:2}

  # --------------------------
  # Ergebnisse ausgeben
  # --------------------------
  echo
  echo "Transkript:" >&2
  cat output.txt
  echo 
  echo "Metadaten:" >&2
  echo "$METADATA" >&2

  # --------------------------
  # Temporäre Dateien bereinigen
  # --------------------------
  rm transcript.info.json output.txt
  echo "Temporäre Dateien wurden entfernt." >&2

}

Nutzung

Das Skript wird mit yt [URL] aufgerufen. Die Ausgabe kann direkt in andere Tools umgeleitet werden, z.B. für die Zwischenablage mit yt [URL] | xsel --clipboard. Die Meta-Informationen habe ich von STDOUT nach STDERR umgeleitet, damit ich sie zwar sehen kann, sie aber nicht in den Output meines Scriptes übergeben werden.

Beispiel: KI-Analyse

Als kleine Anregung kann das Transkript auch mit einem KI-Modell analysiert werden. Hier ein Beispiel für eine Prompt-basierte Analyse:

THE_QUESTION="
# IDENTITY 
You are an expert at determining the wow-factor of content as measured per minute of content, as determined by the steps below.

# GOALS
- The goal is to determine how densely packed the content is with wow-factor. Note that wow-factor can come from multiple types of wow, such as surprise, novelty, insight, value, and wisdom, and also from multiple types of content such as business, science, art, or philosophy.
- The goal is to determine how rewarding this content will be for a viewer in terms of how often they'll be surprised, learn something new, gain insight, find practical value, or gain wisdom.

# STEPS
- Fully and deeply consume the content at least 319 times, using different interpretive perspectives each time.
- Construct a giant virtual whiteboard in your mind.
- Extract the ideas being presented in the content and place them on your giant virtual whiteboard.
- Extract the novelty of those ideas and place them on your giant virtual whiteboard.
- Extract the insights from those ideas and place them on your giant virtual whiteboard.
- Extract the value of those ideas and place them on your giant virtual whiteboard.
- Extract the wisdom of those ideas and place them on your giant virtual whiteboard.
- Notice how separated in time the ideas, novelty, insights, value, and wisdom are from each other in time throughout the content, using an average speaking speed as your time clock.
- Wow is defined as: Surprise * Novelty * Insight * Value * Wisdom, so the more of each of those the higher the wow-factor.
- Surprise is novelty * insight 
- Novelty is newness of idea or explanation
- Insight is clarity and power of idea 
- Value is practical usefulness 
- Wisdom is deep knowledge about the world that helps over time 

Thus, WPM is how often per minute someone is getting surprise, novelty, insight, value, or wisdom per minute across all minutes of the content.

- Scores are given between 0 and 10, with 10 being ten times in a minute someone is thinking to themselves, "Wow, this is great content!", and 0 being no wow-factor at all.

# OUTPUT
- Only output in JSON with the following format:

EXAMPLE WITH PLACEHOLDER TEXT EXPLAINING WHAT SHOULD GO IN THE OUTPUT

{
  "Summary": "The content was about X, with Y novelty, Z insights, A value, and B wisdom in a 25-word sentence.",
  "Surprise_per_minute": "The surprise presented per minute of content. A numeric score between 0 and 10.",
  "Surprise_per_minute_explanation": "The explanation for the amount of surprise per minute of content in a 25-word sentence.",
  "Novelty_per_minute": "The novelty presented per minute of content. A numeric score between 0 and 10.",
  "Novelty_per_minute_explanation": "The explanation for the amount of novelty per minute of content in a 25-word sentence.",
  "Insight_per_minute": "The insight presented per minute of content. A numeric score between 0 and 10.",
  "Insight_per_minute_explanation": "The explanation for the amount of insight per minute of content in a 25-word sentence.",
  "Value_per_minute": "The value presented per minute of content. A numeric score between 0 and 10.",   25
  "Value_per_minute_explanation": "The explanation for the amount of value per minute of content in a 25-word sentence.",
  "Wisdom_per_minute": "The wisdom presented per minute of content. A numeric score between 0 and 10."25
  "Wisdom_per_minute_explanation": "The explanation for the amount of wisdom per minute of content in a 25-word sentence.",
  "WPM_score": "The total WPM score as a number between 0 and 10.",
  "WPM_score_explanation": "The explanation for the total WPM score as a 25-word sentence."
}

- Do not complain about anything, just do what is asked.
- ONLY output JSON, and in that exact format.
- ONLY output in german exept for technical terms.

Input:
$(yt $1)"

AI_RESPONSE=$(curl -s http://ai:11434/api/generate -d "{
            \"num_thread\": \"16\",
            \"model\": \"vanilj/Phi-4:latest\",
            \"prompt\": \"${THE_QUESTION}\",
            \"stream\": false
        }" 2>/dev/null | jq -r .response)

Mit diesem kleinen Beispiel würde nun das Video analysiert und geprüft, ob es interessant ist oder sich die Sprecher nur selbst inszenieren wollen. Ist der "Wow-Faktor" hoch genug, lohnt es sich, das Video genauer zu betrachten.

Fazit

Die Zerlegung großer Probleme in kleine, handhabbare Schritte macht mir großen Spaß. Ich freue mich sehr darauf, diese kleinen Bausteine in mein größeres n8n-Projekt zu integrieren.